Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

>Which to my mind is horrendous. The closure f does not capture the value of i at the time when f is defined, changing i after f was defined make nonsense of the idea of a closure.

Of course it should change i after the closure was defined, since the closure doesn't copy but refer to that i.

Looks like a fully proper closure.

Which language does this differently?



The problem is that closures don't usually refer to mutable entities, and most functional programmers are used to an immutable language. The idea that a closure itself is mutated (its return value can change) just because something outside and separate of it mutated goes against the very heart of functional programming, and is not how functional languages behave at all.


This gets back to the point that Swift is not a functional language. By default, the closure is capturing an immutable reference - the fact that the value might change is implicit to the way you must think about programming in a non-functional language. The mechanism to capture a constant value is to declare it in in a capture list:

  var f = {[i] in print("hello I'm a callback and i =", i)}


> By default, the closure is capturing an immutable reference

I think some imperative languages still refer to those things as closures, which is unfortunate. Capturing a closure then having everything in there mutable kind of defeats the purpose in my opinion. But maybe I've been damaged/spoiled by functional programming and/or have spent to much time debugging issues related to concurrency and shared mutable state.


Wait, What? Immutable closures are way less useful than mutable closures. Immutable closures can pretty much only be used to create thunks. Mutable closures are basically objects.

On the other hand, if your closure depends on global mutable state, than you have a piece of GLOBAL state that is VARIABLE. Sometimes known as the root of all evil.

But maybe I've been damaged/spoiled by scheme and/or not done enough concurrency programming to get your point.


Anytime I see someone claim that immutability is "less useful" than mutability, I know that the individual has not spent a long time working in an immutable language. Because things are tremendously easier when mutation rarely enters the picture. But, it can take some experience to grasp this.


Meh, depends on the situation. Some problems are easily solved in a functional way, some problems aren't, and then there are problems that are best solved using a mixed approach. Sometimes a good old-fashioned for loop (or the equivalent) and stateful I/O is "tremendously easier" to work with than layers of tail recursion and I/O monads. Professional developers are expected to know which tool to use when, rather than religiously sticking to one approach in all circumstances.


I have yet to encounter any problem that would be better served with an imperative for loop or nested for loop than an immutable list comprehension in Clojure, for instance.


Do you have actual science (comparative studies --plural, not some single paper--, etc) behind the assertion of "better" for the functional approach or is it just blind faith?

An empirical observation says that the most important software in the world, including most of the internet infrastructure, OSes, databases, filesystems, office suites, embedded systems and such, powering 99% of the modern era is written in an imperative or OO language.

That's a fact. Whereas "there would be less issues if we had made them in a functional language" is mere conjecture, unless proven otherwise.

Note that common errors such as null pointer exceptions are not only avoided in functional languages for example, but in any imperative language with optionals, bounds checking etc too. So if one is gonna bring those up as something in favor of functional programming they're not giving the full picture.


I've never met a problem where tailcalls were more awkward than loops. But then, scheme kind of pushes you toward tail-calls, so hey.


I think swift really found the sweet spot in this regard by not thinking about mutability but value/reference semantics.

I've found that in swift the things that should be values are and the things that should be references are, rather than taking an all or nothing approach.


Except in swift, a truly value-oriented thought process is hampered by its copy-on-write semantics, which are a far cry from immutable structures found in functional languages.


Value semantics are certainly not ideal, but it is very practical.


hellofunk: Reasoning is easier in functional languages, so fair enough.


Cocoa and Cocoa Touch were designed with imperative programming in mind though, so this is what the creators of Swift had to work with. I think the main use case for mutable captured values is mutable self, in particular the following, extremely common pattern:

    dispatch_async(my_background_queue) {
        do_some_io()
        let result = do_expensive_computation()
        dispatch_async(dispatch_get_main_queue()) {
            self.value = result
            update_ui()
        }
    }


Objective-C does it differently by default:

    int x = 0;
    void (^block)(void) = ^{ NSLog(@"%d", x); };
    x++;
    block();
This will log 0, not 1. If you want to capture by reference rather than by value, you add __block to the declaration of x.

For a lot of people coming to Swift from Objective-C, this is a surprising change, especially if Objective-C was their first language with closures.


That's a block, not a closure. It's still an anonymous function, but the semantics are slightly odd, and derived from Smalltalk, probably altered some.


"Blocks" is what Objective-C calls closures.

A closure is just a function that captures ("closes over") the surrounding scope.

Edit: strictly speaking, the construct here is an anonymous function. Objective-C calls them "blocks" and Swift calls them "unnamed closures" or "closure expressions." Both are, or at least can be, closures. (I'm not sure if the term "closure" can be used to refer to a function that could refer to variables in the enclosing scope but doesn't. Probably not.)


What you seem to be calling a closure refers to a lambda in a lexically scoped language. Particularly when they refer to free variables.

Blocks are in fact lambdas, or at least closures. I was wrong in the above. In some early versions of smalltalk, blocks had some odd semantics that made them different, but this is no longer true. However, judging by the Objective-C example above, Objective-C blocks don't create true closures, as a true closure would have the semantics of the Swift code from the article.


This is only surprising because of the ambiguity of value types in certain cases in Swift. If you passed it to a function and mutated it then it would work as your example. I'm still not sure why they made it work this way for closures. Using reference types closures and blocks are more or less the same.


What ambiguity are you referring to? It has nothing to do with value versus reference types. Reference types have the exact same difference between the two languages. In Swift, mutable variables are captured by reference by default, and in Objective-C they're copied by default. Value versus reference doesn't make a difference. For example:

    NSView *view = [NSButton new];
    void (^block)(void) = ^{ NSLog(@"%@", view); };
    view = [NSTextField new];
    block();
In Objective-C, this will log an NSButton. Translate it to Swift and it will log an NSTextField.

I don't think either behavior is more correct, it's just a fairly arbitrary choice. IMO it's surprising only if you've learned to expect one way because you worked in a language that does it that way, then encounter a language that does it the other way.


> Which language does this differently?

Languages with immutable bindings (the author is one of the original designers and implementers of Erlang)


In fact, he expands on closures in an earlier post (about Elixir):

Proper closures should only contain pointers into immutable data (which is the case in Erlang) - no pointers into mutable data. If a closure contains a pointer into mutable data and you change the data later you break the closure. This means you can’t parallelize your program and even sequential code can contain weird errors.

http://joearms.github.io/2013/05/31/a-week-with-elixir.html


That's just wrong, in most cases. Mutable closures are incredibly useful. Erlang, however doesn't actually need them, because where I (a scheme programmer) would use a closure with mutable state, Erlang programmers would use a process running a function that takes that state as an argument and runs forever, tail-calling itself to change the state. In most languages this is impractical, because most languages don't have erlang's threading semantics.


They are, however, incredibly useful in Erlang. Most languages don't ~need~ closures. The whole point is that they're useful, though.

Haskell doesn't have mutable state; it still has closures.

Mutable or immutable is somewhat orthogonal; I admit, coming from Erlang to Javascript I was -shocked- and very facepalmy when I learned that closures close over variables that can still vary. That is, I couldn't just pass back a function and expect it to behave the same way depending when I called it. I had to add an additional scope in place and bind the values anew (i.e., a new function, passing the values being closed over into it as params). Immutable is much easier to reason about, much easier to write with, and despite being more limited in what you can do with them, I'd argue just as useful. Everything it prevents you from doing there is some other, safe way of achieving; the same as comparing mutable vs immutable in other contexts.


They don't do it differently, they simply avoid the question by not letting you change any binding ever. In languages that embrace immutable bindings but don't enforce them, like scheme, closures work exactly as the parent describes.


> Of course it should change i after the closure was defined, since the closure doesn't copy but refer to that i.

Well it should not allow it and make ia clone / copy-on-write thing /etc. Calling that a closure sounds broken. Just like Joe points out.

> Which language does this differently?

Haskell, Elixir, OCaml, Erlang


No, those languages just don't allow you to modify state. In non-functional languages like swift, you can modify state, and closures respond to that.

What I think a lot of people fail to understand is that a closure is not a special object, with magical powers, but a direct consequence of lexical scoping: closures just follow the lexical scope rules, even if their lexical scope isn't within the current dynamic scope. If a variable within the closure's lexical scope changes, the closure won't keep the value the same. Here's an example of these semantics in C:

  int global = 4;
  void oh_noes(){
    printf("%d", global);
  }
  global++;
  oh_noes(); //prints 5
If somebody complained that the function oh_noes should print 4 in this example, you'd think they were insane. Closures actually work in exactly the same way.


> What I think a lot of people fail to understand is that a closure is not a special object, with magical powers, but a direct consequence of lexical scoping:

That is how it is implemented. It doesn't have to be, I have a list of example languages where it is not the case.

> What I think a lot of people fail to understand is that a closure is not a special object, with magical powers,

Maybe that's why I like functional languages, it does seem like they have magical powers ;-) there.


> That is how it is implemented. It doesn't have to be, I have a list of example languages where it is not the case.

No, you don't. Closures in those are also a direct consequence of lexical scoping. But those languages don't have mutable variables, regardless of closures.


> No, you don't.

Functions defined in modules in Erlang are different from closures. Here is a example:

   -module(e).
   -compile(export_all).
   f()->  1.
   g()-> fun ()-> 1 end.

   $ erl
   > c(e).

   > erlang:fun_info(fun e:f/0).
   [{module,e},{name,f},{arity,0},{env,[]},{type,external}]

   > erlang:fun_info(e:g()).  
   [{pid,<0.42.0>},
   {module,e},
   {new_index,0},
   {new_uniq,<<136,230,191,77,132,145,66,52,216,215,111,24,
             18,188,4,169>>},
    {index,0},
    {uniq,71775738},
    {name,'-g/0-fun-0-'},
    {arity,0},
    {env,[]},
    {type,local}]
To get info on e:f it has to be become a closure-like object, but if you see internally it is still represented differently than a closure.

> Closures in those are also a direct consequence of lexical scoping.

Not sure what you mean a direct consequence. Are you saying that closures follow scoping rules? The point was that it doesn't necessarily follow that they have to be implemented as object instances in object oriented languages, or function pointers, or functions (say like in Erlang).


Well, yes, closures can be implemented however you want, in a true lexical scoped language, every function is a closure, not just lambdas, only most don't really close over anything, and can be optimized away. The case of C is, again, instructive.

    //foo.c
    int global = 0;
    int quuxify(){
        return global++;
    }

    //bar.c
    extern int quuxify();
    printf("%d", quuxify());//prints "0"
    printf("%d", quuxify());//prints "1"
even though quuxify() depends on global, which is out of scope in bar.c, the call still compiles. Why? because C is a lexically scoped language, and so variable references in functions refer to the scope the function was declared in, NOT the one it was called in.

And you thought C didn't have closures ;-D


It's a bit weird. I don't think Joe would have an issue with mutating the closed over variable, but having the closure just be the binding rather than the value, and then being able to rebind it to something else seems brittle.

> Which language does this differently?

Rust does it this way but in a less error prone way due to its sophisticated ownership tracking. If you close over a variable in the environment, it gives the ownership to the closure and you can't then rebind it outside.


He's not saying that closures over mutable variables is a bad thing in Swift. He is saying it's a bad idea in any language, even though most languages with closures allow it.


I see how programmers can mistake mutable closure references for immutable, but if we imagine that this confusion is solved somehow (for example, closures copy values by defualt and reference only with a special keyword), how is it bad?


This behavior is one of the reasons not to call JS a 'functional' language, IMHO.


Well then scheme isn't one either. But then, scheme isn't one. And javascript is just a language in which the functional paradigm is common. it's a multi-paradigm language. Anybody who says otherwise doesn't know what their talking about.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: