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.