The Chaos Programming Language
chaos-lang.org
chaos-lang.org
It doesn't even show methods or things like that. I think 90% of the docs I've read so far should have just been a single page with one liners one after the other, and less interesting stuff that's got more depth should go further back. I don't think showing nested arrays and dictionaries is interesting to me after you've just told me about some super interesting testing / correctness stuff - lead with that!
I skipped ahead to Decision Making. I think the example is so strange and contrived - three functions, each returns some number above 100, some logic after that that feels arbitrary? I would do something at least a little more universal like fib.
The end of this section states "100% testable" - I'm confused. Why is this testable?
I could not write one unit test to have 100% code coverage, not even line coverage.
If I, for example, wrote a test that used the code provided, with an assertion
assert add(3, 5) == 101
I would not hit f2 or f3, so I'm confused by: "A single unit test is enough to have 100% coverage on functions, always."
That unit test was definitely not enough for 100% coverage.
I skimmed the rest.
For a language that states it's great for testing and preventing errors, I am at a loss as to how one would write a test for it, or handle an error.
This looks like a pretty neat language, but you really gave me such a good hook and then no follow through.
(You're not testing the conditions that lead to calling one of the `f` functions. Maybe it's chalked up to integration testing?)
But yeah, I share much of your frustration. The Decision making section should be the first thing, and it should have a test example. Longer non-trivial programs examples should be contrived to reassure people that this not utterly impractical.
As you say, there's full line coverage for tests, but no guarantee of full equivalence-partition coverage. It's quite possible for branch-free code to fail on certain values. ctrl-f for overflow in [2]
The 'Showcase' link is broken, the GitHub repo seems to show no examples, and the linked StackOverflow chaos tag is never used in relation to this language, so as you say, I'm not sure how serious this language really is. Fun idea though.
(It's entirely possible I'm misusing the term boundary-value analysis. Corrections welcome.)
[0] https://chaos-lang.org/docs/11_decision_making
Firstly, there's the name: chaos, which evokes the opposite of what my code to look like.
Secondly, the first three "features" all come across as deliberately goofy to me. The first two promise seeming implausible things: zero cyclomatic complexity and always 100% test coverage. The justifications for these promises seem bizarre: only function returns allow decision making? (A seemingly terrible place to make decisions) One test is always sufficient to have coverage? It isn't object-oriented? (Obviously, a lot more to functional then that)
The full name is "The Chaos Programming Language", which I understand as "the language to program chaos". It's in line with the motto "Turn chaos into magic!", as you program to turn an arbitrary state (chaos) into what you want (order / magic).
I still think it's a joke language, but this part is well-thought.
> Decision making(a.k.a. control structures) in Chaos language is only achievable on function returns for the sake of zero cyclomatic complexity.
...
> At first glance, defining the control structures in this way might seem so unnecessary or inconvenient but this is the pinnacle of writing 100% testable, clean and error-free code in any programming langauge by far.
I’m skeptical about this claim. I’m not sure I believe 100% error-free is possible in any language.
Can someone please elaborate on this claim?
Of course, there are some qualifications one should make regarding such a claim: you have to trust that your specification is "correct", that your hardware is functioning correctly, that the proof checker didn't accept a bogus proof, that the underlying logic (e.g., the calculus of inductive constructions) is consistent, etc. That's a lot of things to trust, but the point is that you don't have to trust yourself.
So, it is not really fair to downplay the chance that you could have a wrong specification, although it would be equally wrong to use that as an excuse to downplay the value of Coq.
If someone is just saying "This is a formally verified protocol" without what they actually checked for, they are salespeople not mathematicians.
"The authors of the KRA paper were able to understand what the proofs were about, and why they don’t cover the KRACK vulnerability. Even though the original proofs didn’t reveal security flaws, a principled approach would use these proofs in order to discover where to look."
https://galois.com/blog/2017/10/formal-methods-krack-vulnera...
But I think the idea is that by forcing each branch in a case to be an separate function they are forced to be unit testable.
Edit: If code needs certain number of conditions, they will be there in this or that form, that cannot be avoided. I would like to see real benefits of their choice in real non-trivial examples.
I only wonder how it would feel using it on real world problems.
One question to the author: is there string interpolation?
world = "world"
print "hello #{world}"
Finally, the links in the Docs section of the footer are 404 and the link to GitHub links the home page of GitHub, not the project.---
> kaos> num a = 5
> kaos> a = 7
> kaos> print a
> 7
Doesn't that mean a is mutable by default?
It would be mutable if it allowed something like this:
> a = 5
> a.add(1)
> print a
6
Note that numbers are immutable in most languages anyway. Arrays, hashmaps, and sometimes strings are the data types that are frequently mutable.> 3 = 5
> print 3
5
The end
But given that it's not an object oriented language, how could any variable be mutable given your example/definition?
How could you mutate a variable in a way that this language disallows?
I presume something like this:
array a = [1, 2, 3]
a.append(4)
Names are mutable, but the values they point to are not.> Arrays and the elements of arrays are also immutable
I guess the docs need a bit of rewording. Forcing a deep-copy on variable assignment does not mean the variable itself is immutable.
https://www.amazon.com/Purely-Functional-Structures-Chris-Ok...
> Chaos language is not object-oriented. So everything is done by functions and data types.
a[0] = 1
Would be a better example. Appending to an array could involve creating a new array and reassigning it to ‘a’. function add(x, y) {
return x + y
}
a = 5
add(a, 1)
print(a)
A language printing 6 is pass by reference. A language printing 5 is pass by value.
Both would print 6 for this code a = add(a, 1)
print(a)
However a language like Erlang would end with an error when trying to reassign a new value to a. function add(x, y) {
x = x + y
return x
} GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
Prelude> a = 5
Prelude> a = 7
Prelude> print a
7
But yeah, it doesn't seem like there's any support for first class functions either, so perhaps just a bit too much creative license in marketing? λ> let foo = 1
λ> let foo = 2
λ> foo
=> 2
could be rewritten[2] as λ> let foo = 1 in ( let foo = 2 in foo )
=> 2
which makes the semantics more clear.This idiom is also quite common in Clojure, another famously immutable-first language:
(let [foo 1
foo 2]
foo)
;; => 2
In my opinion (predominantly informed by my experience with those two languages contrasted with the usual suspects from mutable-OOP-land), the benefit of immutability isn't what's happening in your own local scope, since it's typically quite easy to track what your immediate context is doing to a variable. Instead, it's the language-enforced promise that the only changes to local values can come from local actions: your function and method calls can never have spooky side effects, nor can other threads if you're in some hellish concurrent environment.In this light, Chaos's apparent syntactic sugar of
a[15] = 44
to mean (using some hand-wavey pidgin) a = a.updateAt(15,44)
seems quite reasonable and fully in the spirit of immutability as a meaningful language feature.[1] In my scratchwork project, my repl actually yells at me with an annoying warning about this:
<interactive>:8:5-7: warning: [-Wname-shadowing]
This binding for ‘foo’ shadows the existing binding
defined at <interactive>:6:5
[2] I believe that the haskell repl actually functions like a do-block, so the pedantically correct desugaring possibly involves lambdas and bind, but that's not really an interesting distinction here IMO and makes the example less clear.From my experience any sufficiently badly written code is hard to understand even in the local scope. The bar for hard to understand code isn't that high because the complexity of well written code is very close to zero.
Most code that avoids reassignment can be read from top to bottom. Code with local mutation can require backtracking and then the complexity can start exploding but that doesn't necessarily apply to code with mutation across functions. A simple list.add() doesn't cause anyone's brain to melt.
A classic is that someone writes a for loop like this: for(;i < 10; i++). You now need to go back and check what the start value of i is even though 99% of the time it is 0. Then you need to check if the counter is used for anything after the loop has exited because sometimes a loop is just trying to find the first element that matches a predicate. Now imagine if the i variable gets reused by a second loop. You now must check if the i variable is resuming the loop at the same position by backtracking. Every single line of code has the potential to amplify the complexity of the entire function.
All that meaningless complexity has no reason to exist. It doesn't provide any value and it doesn't cost anything to avoid it.
int a = 5;
a = 7;https://chaos-lang.org/docs/11_decision_making
> Decision making(a.k.a. control structures) in Chaos language is only achievable on function returns for the sake of zero cyclomatic complexity.
This looks as original and language-defining as Rust's borrow checker. I really wish authors changed their docs accordingly. Everything else is pretty standard on a conceptual level, but this still has me thinking whether it's a work of pure genius, a joke language or both.
I came up with this idea of designing a language with no "if" after dealing with various untestable codebases for years. They were literally untestable because of the technical debt caused by the extensive amount of "if" usage in the function bodies, especially the guard clauses makes it 1 "if" minimum for almost every functions. So at the end I have exhausted because of the if(s) and decided to create a language that forces you to have minimum technical debt.
I guess case/cond can be implemented with the return mechanism of Chaos. Maybe it's going to feel weird, maybe not.
There is no pattern matching and I got the feeling that's going to complicate things but again, it can be emulated to some degree but the return mechanism. Instead of
def a(0), do: "a"
def a(1), do: "b"
def a(_n), do: "c"
Probably we'll be writing str def a(n)
num x = n
end {
x == 0 : "a"
x == 1 : "b"
default: "c"
}
Having to define that x variable feels like a waste of code and reasoning on x instead of n (the argument of the function) is a pity. Maybe the function body can be empty. I didn't install the language.I wonder how that scales on real world cases, for example matching the internals of some complex data structure.
Even ignoring that issue, even if the control flow statement is in the return, it still has a cyclomatic complexity of 2. I.e. function isEqual(x, y) { return x == y } still has a cyclomatic complexity of 2, you're just hiding it. The actual logic flow in terms of nodes is
``` if (x == y) { return true } else { return false } ```
It's entirely possible for a single line to have a cyclomatic complexity of more than 1. Ternaries, for example, would have a cyclomatic complexity of 3.
I'm not so sure it's original; many compilers work on ASTs whose nodes are a sequence of non-branching operations terminated by a branch. Though people don't use these internal representations as "programing languages" but afaik they technically are.
You might even say they are arcane.
This page shows how to do an add function: https://chaos-lang.org/docs/11_decision_making
On another note, the docs are not so good. They're really missing a few real life examples with unit tests.
how do I create a new array with a new value
there is GC or Structural Sharing?
Also, there is lambdas? Force the developer to create a function for each "conditional" loop costs the habit of bad function naming.
This is just moving the control flow to the end of the function right? Switch-case statements also have cyclomatic complexity, right?
Maybe some unix pros here can tell me, why the occultist package manager not installed via sudo, but the language itself is? It seems like an unnecessary security risk to run sudo on a random download.
There are a lot of alternative keywords, especially for type safety and function definition related keywords, with the purpose of attracting programmers from other programming languages and making them feel at home. At least that was the intention.
It isn't that alien of an idea in my mind as most people here in the comments seem to argue. I suppose if you used a function with only an "end" clause a function would end up mostly like how one generally writes functions in most functional languages, where a lot of functions are fully comprised of a switch/match on the input. Maybe because the syntax is very Ruby-like you see a lot of people here expecting more object-oriented design.
But all the aliases need to go. What's the point of having three aliases for an import statement other than to confuse new programmers. It seems like one of those ideas that seems good on paper, to include words from first languages, but in the end it'll just end up confusing everybody.
The only thing I dislike are the blinking colored messages.
And maybe the list alias for array is extremely confusing, esp. when he wants to add real lists later. Or lazy lists. json for dict maybe, why not.
I'd rather have another "dot directory" like ~/.occultist than have some random package manager take over my entire /usr/local.
Is the renaming from hello.kaos to dev.kaos intentional?
TypeScript's type safety
Python's syntax, modules and extensibility
JavaScript's availability
Ruby's loops and blocks
PHP's dedication to server-side
Haskell's immutability
C's speed
NumPy's matrix arithmetics
Perl's regex engine
Ehh, they forget to add another:Will be used for exactly zero real-life production projects.