Your programming language is probably unproductive
bart-sokol.info
bart-sokol.info
How can you correctly solve problems without being able to look at your code and reason, instantly, about what is grouped together. Let alone tracing through your code but just seeing what statements are grouped with what.
One such suggestion, as provided by the author, is whitespace.
I can't tell you how bad of an idea this is. Just from a teaching perspective. I help tutor for CS100 at my university and a large part of the errors I have to deal with are whitespace errors. People don't understand where a block starts and ends. It's less key strokes but that doesn't mean it's easier or better.
> Languages like Java and C# made it to the almost ridiculous point where not only we have to be very explicit about every aspect of our code, but also made us split this code into an endless amount of files
I see no issue with splitting up a problem into multiple parts that, if sufficiently different, could be hidden from each other.
In the end, I don't think a language can be (un)productive. A language is the means for expressing a solution. Your job as a programmer is to conceive a solution to a problem and pick a language that will best let you express that problem.
Some times functional languages are better at this, some times other languages are better. The thing we should be arguing about is what is best expressed in which language.
Aside from a short "if" statement, I now no longer think it's sexy to abandon ending notation whether it be braces, elements, etc.
Basically they had
if (x)
then()
and went back and did if (x)
new_call()
then()
and caused an error that happened silently.This is something you definitely want to avoid and I personally don't trust myself, after a no-sleep code fixing bender, to remember to add {} around something if I'm editing an if. I'd probably forget.
Again, I'd say shorter does not mean better.
if (x) then();
If you add another statement to the if, its obvious from the indent that you need to use braces. say "yes" if $condition;
if ($condition) {
say "yes";
$affirmative++;
}if (x)
^~
9 : note: ...this statement, but the latter is misleadingly indented as if it is guarded by the 'if'
then();
^~~~
Oh yea, undefined behavior. Do you like using undefined behavior?
It is perfectly acceptable, and in fact considered proper engineering practice, to compile with multiple compilers to take advantage of their warning and static analysis capabilities.
If you have a page with enough elements and nesting going on that indentation doesn't make its structure clear, I find it hard to believe that you'll see </div></div></div> and think "oh yes, I just closed <div class='wombat'>".
A good editor may highlight the region that a </div> covers, and/or show the opening element and/or the "path" to the current element in the status bar.
But, a good editor that understands indented syntax could do the same. It is a fault in code editors that they don't often have good features for navigating around source which uses indenting. This isn't a problem with the syntax.
FWIW, I use SLIM - which is a Jadelike language for Ruby - and I hate having to deal with raw HTML. I find it incredibly hard to navigate, primarily because of the lack of indentation. All too often you think a particular block is contained in some element but it turns out it just looks that way because somebody decided to use indentation whitespace decoratively.
I'd go so far as to say breaking a problem up into black boxes that solve smaller parts of the problem is one of the most basic skills in programming.
On the flip side, when I was in school and a peer asked me to look over their code, it was usually an unindented mess and they still very much had no idea "where a block starts and ends" despite the braces.
When Python was introduced, I was hopeful that a technical demand that indentation be done properly might actually help, pedagogically. On reflection, imposing this at linting with a brace-based would probably be better still, as the error messages could be substantially better targeted.
Here's the thing when it comes to language design: Define a single way to do something. Yes, be politically incorrect and realize you might hurt some people's feelings if you make braces mandatory. Or make them close their tags on HTML. But in the end, what you're adding is simplicity: The arguments move from "you don't write code the way I do" to other more important things.
Some people like braces, like me. It doesn't matter at the beginning/middle of a code block much, but the clearly visible terminating } is what does it for me. I need that.
If every whitespace significant language had strict formatting standards, shipped with a formatting utility (e.g. gofmt), and actually enforced formatting standards everywhere (including stuff like number of empty lines between functions, etc...), then I would be on board with no braces and whitespace significance. Until then, the inconsistencies you run in to in whitespace significant land just don't work for my brain.
Then, some people hate braces and love whitespace significance. Cool. doesn't matter. the end.
Either way, opening an article that says "Your programming language is probably unproductive" which immediately devotes itself to whining over pedantic syntax bullshit...makes me not want to read it.
A while ago I started writing something about meter in programming languages; what could we gain by thinking not just about making them look more like English but more able to be read aloud? I didn't come to any useful conclusions, but I do note that of all the unpronouncable symbols we use the semantic whitespace of python is the most difficult to convey adequately.
It's also probably more productive for that purpose than almost anything else. Why? Availability of tools, and also fitness for use. You usually don't really want to be using Python, say, in that environment, because you don't want to have to burn an interpreter onto your device, and you don't want the runtime inefficiency, and and and...
I wouldn't be in favor of a programming language that tried to enforce verbalizability (I'm thinking something like basic here). But I do think that having a program "tell a story" is a boon for comprehension. Have operations, variable names, function names, choice of where and when to use a function, etc be in such a way to optimize the narrative quality of the code. But I don't immediately see a way for the language construction itself to benefit here. I think having clear structural code is a boon to quickly scanning and understanding the structure of code.
Implicit partial application is a poor idea that makes programs incomprehensible. If you pass only three arguments to a four-argument function foo, you should see a "foo: insufficient arguments" error, and not a function of one argument popping out.
The semantics of obtaining a partially applied function doesn't depend on syntax. It can work fine when function arguments are delimited by parentheses. For instance, suppose that if we write (cons 3) we automatically get the equivalent of (lambda (x) (cons 3 x)). That's partial application, with parens. We can then do (mapcar (cons 0) '(1 2 3)) and get ((0 . 1) (0 . 2) (0 . 3)). Is that a good idea? Firstly, we lose variadic functions and functions with optional arguments. (list 0) can't return a lambda; it already has a meaning; (list) produces the empty list, (list x) a list of one element which is the value of x, and so on. We could end up with an embarrassing proliferation of fixed arity functions like list1, list2 and list3.
It's not that much of a chore to have an explicit partial application operator: Say:
(op list) -> (lambda (. args) (apply list args))
(op list _ 1) -> (lambda (arg) (list arg 1))
If that is too verbose, and used often, we can dedicate alternative closure punctuators to it: {list} -> (op list)
{list _ 1} -> (op list _ 1)
So braces now help with partial application, enabling it when we want it. The notation keeps code crystal clear because everything is delimited. We know that (op foo 1 2 3) or {foo 1 2 3} partially applies exactly three arguments to foo, no more or less, and we know that (foo 1 2 3) calls foo with exactly three arguments.Tho admittedly, most LISP libraries tend to strive for the same age as LISP itself, as it looks.
Although I admit that Clojure is a decent language.
However apart for that, and also dislike the use of space and implicit type. I use F# and like it, except for how ambiguous is for a lot of things.
What is the point of have a super-strong type engine and when you look at:
let getProductById repository id
You still need to use intelli-sense or check the code as with dynamic languages? If I'm into a static typing, I wanna fully use it.
When I see:
getProductById repository id
Type inference defeat me as a user: The computer know what that is, yet, is hidden from me. Not much different than in dynamic languages. Ah, you can annotate it if want! But then you break the language convention. Is bad to let the user decide, because then everyone will decide, but different.
So, I think is better in a type-static language to annotate the types, all the time. Because that is how the language really is, and is the way to unlock the benefit of better documentation/clarity that is one of the benefits of static type.
This is my main gripe with F#/OCalm.
Also apply code require gymnastic because something is unclear in a secuence:
let result = getId code save result bla bla
When things start or end?. And F# have let fun = and let fun()= both things different. This create a compile time bomb where call some effect trigger before things are ready.
In short: have a way to group and mark blocks is great. Python is closer to how do things with space/indentation. -----
Syntax is very important. I don't dismiss it like other people that think is just "sugar".
Syntax is our user-interface. When is closer to what the language is, better.
I agree. ((int)((int) 5) + ((int) 5)) - ((int)2) is way clearer than 5 + 5 - 2.
And by the way, a + b + c is not more clear than Int + Int + Int... or sum(customer, products) vs. sum(Customer, ProductArray)
We should omit the type from intermediate expressions when (and only when!) it will be sufficiently clear from context and it does not serve as a clearer specification of intent than your terms. I contend that this is not a special property of expressions.
The issue with braces is that many languages allow multiple lines and indentation when there are no braces. If languages required you to either say "if (foo) bar()" ON ONE LINE or use braces, 99.2% of all the issues would disappear. Heck, I’d be in favor of a new C17 standard just to add this restriction.
For large programs, making the computer instantly tell you where you remembered wrong is more important (like Haskell, as well as Pascal, C++, Java, C#, etc.)
By comparison, small syntactic differences fade into the background noise. This is not news.
I can see in a fraction of a second what the first one does. The second one? 3-4 seconds to be about 85% sure I know what it's doing, and about 6-10 to be certain.
return id > 0 and repository:get(id)
Also in C you can #define maybe(cond, ptr) ((cond)?(ptr):NULL) macro and use it everywhere.I still have no idea why.
What other paradigms are highly regarded among hackers?
None, but hybrid object functional languages have been on the rise in recent years (though, like FP based languages, still very much niche). See Scala, Ceylon, OCaml, among others.
Language functionality aside, multi-target is the next great wave. For example, came across this today[1], pretty awesome -- compiles to server-side, client-side, and native!
Would be quite nice to write-once run literally everywhere with a single language, but that looks to be a couple of years off (if there are production ready tri-target languages out there, I'd like to check them out).
[1] https://github.com/mkotsbak/scala-native-tellstick-example/t...
Granted F# is backed by .NET so it has access to a large existing ecosystem (on Windows) which makes it fairly productive ... once it has been learned.