This is an interesting thread.
A couple things struck me that I want to comment on.
Iâm all for defining function blocks with {}. I donât think anything has to separate functions from any other code block because theyâre semantically the same. Theyâre not implemented the same way for performance reasons, but a compiler can tell how youâre using the block without annotation. (If it comes after while and itâs not assigned to anything, itâs inline. If itâs assigned and referred to elsewhere, compile it as a closure.)
Autoclosures are an awesome compromise between lazy and strict evaluation, which gives you significant power to create new language features. You just have to assume that every library author is smart and sane and friendly. Which I do.
Iâm also all for the consolidation features @senocular proposed. You can almost do it automatically with code thatâs commented for clarity. Take kirupaâs post on merge sort in JavaScript:
function mergeSort(input) {
if (can't divide further) {
return input;
}
divide the array in half
recursively sort and merge
}
function merge(left, right) {
var result = [];
order the sublist as part of merging
add the remaining items to the result
the sorted sublist
return result;
}
(which isnât perfect, but as you can see, could be super readable with a few tweaks.)
Iâd like to do away with the requirement that you must name something to refer to it in more than one place. Tuples are records without keys. Why not variables without names?
The language would support Jonathan Edwardsâ schematic tables (conditional logic written as truth tables) (screenshot). They make logic like in your example:
if hiddenCondition {
hiddenMethod()
} else {
if hiddenCondition2 {
hiddenMethod()
} else {
hiddenMethod2()
}
}
and every equivalent form, such as:
if hiddenCondition || hiddenCondition2 {
hiddenMethod()
} else {
hiddenMethod2()
}
all collapse to the same structure, which is easier to reason about, refactor, and maintain. (Iâm having trouble convincing myself that the second version is actually equivalent to the first, even though Iâm pretty sure it is. This is why notation mattersâŚ)
Also, we love to rag on Java, but Iâve been writing Java at work all day and I have to say that dependency injection is amazing. It is the programmer equivalent of reaching out from under the car, announcing, âsocket wrench,â and having one materialize in your hand. As far as Iâm concerned, we should be injecting everything everywhere always. Decouple all the things!
The language would also let you inject the user. If youâre not sure how to implement some behavior, inject yourself and be in charge of turning the parameters into a return value and side effects manually. You can abstract and encode that into a programming notation laterâŚ
And this isnât an idea for a language, but itâs something I keep in mind when Iâm thinking about ideas for programming languages: cognitive dimensions of notations. In particular, programming is not one activity. Itâs several (writing, reading, debugging, etc). And âeach activity is best served by a different trade-off in the usability on each dimension.â In fact, if I could write code in Ruby, but refactor it in Haskell, debug it in Smalltalk, and deploy it in JavaScript, that would be great.
Thatâs why Iâm right on board when @krilnon says programming languages shouldnât round off every corner in the name of protecting us from ourselves. Because they shouldnât ⌠up until the point when we move from designing and writing code to maintaining its current behavior. At that point Iâm all for language features that help you not accidentally break things.