" If you like functional languages, you should be using Coffeescript instead of raw Javascript. And if you prefer promise based programming instead of callbacks, you should be using Iced Coffeescript. "
" Of that list, here’s what JS has:
Minimalism. Dynamic typing. First-class functions and closures.
Don’t tell me it’s got lexical scope, because JavaScript’s? scoping is an abomination in the face of God. Guy Steele isn’t even dead and JS scope makes him pre-emptively roll in his not-yet-occupied grave.
...
At the same time, we’re ignoring the things about JavaScript? that make it not Scheme. It’s got a much richer syntax including a great notation for data. I’m not a huge fan of prototypes (anymore), but it’s an interesting dispatch model that Scheme doesn’t have. "
-- http://journal.stuffwithstuff.com/2013/07/18/javascript-isnt-scheme/
"JavaScript's C-like syntax, including curly braces and the clunky for statement, makes it appear to be an ordinary procedural language. This is misleading because JavaScript has more in common with functional languages like Lisp or Scheme than with C or Java. It has arrays instead of lists and objects instead of property lists. Functions are first class. It has closures. You get lambdas without having to balance all those parens." -- http://www.crockford.com/javascript/javascript.html
"
Avatar danielparks • 4 days ago
Could you expand on your contention that JavaScript? isn’t lexically scoped? 3 • Reply • Share ›
Avatar Calvin Metcalf danielparks • 4 days ago
It is functionally scoped instead of block scoped and while it is mostly lexically scoped 'this' is dynamically scoped. 6 • Reply • Share › Avatar munificent Mod Calvin Metcalf • 4 days ago −
Not just that, but thanks to with and the global object, you always have dynamically scoped variables. 1 • Reply • Share ›"
"
Avatar Chris Howie • 4 days ago
(I mentioned this to you on Twitter already, but figured I'd repeat it here for the sake of discussion.)
Overall a very good read.
My only nitpick is that Java 8 does not have closures. It has these lambda things that resemble closures, but they are not any more closures than anonymous classes already were.
Anonymous classes can also reference variables in the parent scope if they are declared final. The only way in which lambda syntax differs meaningfully in this regard is that you don't have to declare the supposed upvalues as final -- but they *are implicitly final* and so are no different in that regard except that you don't have to go around slapping "final" on your locals. But just the same, you cannot modify them.
"For both lambda bodies and inner classes, local variables in the enclosing context can only be referenced if they are final or effectively final. A variable is effectively final if it is never assigned to after its initialization." -- JSR 335 http://cr.openjdk.java.net/~dl...
If one wants to call this "closure" then it's a pretty half-assed, mostly-useless form of it. 5 1 • Reply • Share ›
Avatar Alan Malloy Chris Howie • 4 days ago
Haskell's and Clojure's closures have the same limitation (because literally every local variable is final), and are pretty dang useful. Anonymous classes are tremendously verbose and painful to use, but they're perfectly serviceable, and I presume the syntax sugar in Java 8 will make much much more tolerable. 7 1 • Reply • Share › Avatar Chris Howie Alan Malloy • 4 days ago
Agreed, it is syntax sugar. But to suggest that "now Java 8 has closures" ignores the fact that Java 8 lambdas are simply syntactic sugar for anonymous classes (which themselves were already syntactic sugar).
My point is that Java 8 either had closures before lambda was introduced or it doesn't have closures at all. The addition of lambda syntax doesn't change anything in this respect, it is simply a syntax specialization for the "anonymous class with one method" case. Rules regarding upvalues have not changed. There seem to be a lot of people treating "lambda" and "closure" as synonyms when they are anything but. 3 • Reply • Share › Avatar Ricky Clarkson Chris Howie • 4 days ago
I avoid the overloaded term 'closure', but Java 8 will have lambdas, and the 'effectively final' restriction will make using lambdas to create new control structures harder, but will avoid some confusion.
var list = [];
for (var a = 0; a < 10; a++) list.push(function() { return a; });
list[4].apply() - what does this give? Confusion. • Reply • Share › Avatar Chris Howie Ricky Clarkson • 4 days ago
It gives 10.
The confusion here is on the part of the programmer not understanding (a) how closures work, (b) the lifetime of variables in JavaScript, or (c) all of the above.
As an aside: In the case of C#, they fixed this case in version 5 of the language by having the foreach iteration variable logically exist inside of the body of the loop. (This compiler logic is only triggered when there is a closure capturing the variable, so there is no performance hit when not using closures.) This demonstrates that this problem can be fixed at the language level without shooting down a very useful feature.
I do understand your point, and this is something that has long been debated. But even if the language can't be changed, this problem can be "fixed" by simply adopting a discipline: don't close over iteration variables. I think it's rather silly to cripple the value of this feature because those unaccustomed to it make mistakes.
Concurrency issues (deadlocking, race conditions, etc.) are considerably more complex than upvalue issues and are much harder to diagnose, and those can be solved by adopting disciplines (always acquire locks in the same order, for example). I fail to see how this case is so different. see more 2 • Reply • Share › Avatar Ricky Clarkson Chris Howie • a day ago −
The point of the example is to show that a small misunderstanding can lead to a big surprise. It's presumably a big enough problem if C# made a backward incompatible change to protect its programmers from some of the impact.
To look at it from another angle, when do you need to close over mutable local variables? Implementing a 'timeThis' function that runs a block and dumps some execution time diagnostics is the classic example:
var timeIt = function(block) {
var startTime = new Date().getTime();
var result = block.apply(); var endTime = new Date().getTime(); dumpSomeStuff(startTime, endTime); return result;
}
then in calling code it would be useful to be able to write to mutable variables, as otherwise you need to change code to be able to use timeIt. You might also be annoyed that 'return', 'break' and 'continue' don't work inside the profiled block, but let's concentrate on variables.
For Java, the earlier BGGA proposal found good ways to deal with such control structure uses of lambdas, but there were some valid and some immature reactions to that in the name of simplicity, and so the control structure uses disappeared from the scope as far as I can tell.
So assuming you're not writing something like timeIt or inventing a new kind of for loop using lambdas, I don't think Java 8's 'effectively final' restriction is going to hurt that much, and I expect it to prevent a number of bugs.
Mutability and flow control operators (return, continue, break) do cause some complications, and just saying no is probably about as good as trying to support everything. see more • Reply • Share ›"
" I’m happy that I chose Scheme-ish first-class functions and Self-ish (albeit singular) prototypes as the main ingredients. "
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
---
_pferreir_ 7 hours ago
link |
Every language has its quirks. Python is not perfect either. But JS shows clear signs of bad design decisions, such as the behavior of the == operator.
reply
woah 6 hours ago
link |
What == does is pretty simple and easy to understand. If you have a hard time with it, use ===. Problem solved.
reply
georgemcbay 5 hours ago
link |
The problem is that JavaScript? does not exist in isolation, there are other languages that use this operator. If you're familiar with any other C-derived language, the way == acts in JavaScript? is very unexpected
... Another example: the way 'this' scoping works is similarly busted in that while the rules for it are reasonably straightforward in isolation, it is different enough compared to other languages that share the same basic keywords and syntax that it should have been called something else.
---
jiaweihli 5 hours ago
link |
That one is somewhat reasonable (and relatively obscure code you'd probably never write).
A more realistic example: inner classes can't see class variables from their enclosing classes. (Why enclose classes? - builder pattern)
reply
-- " This is probably the reason for Javascript's popularity, but if you ignore some bad language design, Javascript is a very simple language with a very small number of concepts that you need to understand to start getting work done in it. Even Python (which I think is the simplest of the widely used dynamic languages) has a larger number of concepts that you need to understand than Javascript. "
--
Exactly like Javascript in this regard. I've been programming JS for over 15 years, and with the exception of cross browser support back in the day, there's nothing that had me startled after I learned the language -- except for a few issues related to floating point that I stumble upon now and then, but then that would be true for floating point math in any language.
--
samth 1 day ago
link |
You should have a look at Typed Racket [1] which is a type system for an existing language (Racket) built entirely with macros [2] that satisfies all of the criteria you want -- works with the IDE, safe interop with untyped code, etc.
[1] http://docs.racket-lang.org/ts-guide/ [2] http://www.ccs.neu.edu/racket/pubs/pldi11-thacff.pdf
reply
klibertp 20 hours ago
link |
There's also TypedClojure?