Hacker News new | past | comments | ask | show | jobs | submit login

I don't get the business of marking variables as const in local scope (aka "val" aka "final" for local variables). It's easy for a parser or a person to scan the local scope and see if a variable is ever possibly mutated or not. This is very different from the situation with globals where it's generally intractable to prove that something is never mutated. In local lexical scope you can see all possible mutations by the definition of "lexical scope": a const variable is one that is assigned only once, a non-const variable is one that may be assigned multiple times – this is a straightforward syntactic property. Is there some benefit to marking local lexical variables as constant that I'm missing?



At least in Java, non-final variables can't be used inside anonymous inner classes. Also, it's easier for me as a developer to read "final" and know that (referential) immutability is guaranteed by the compiler instead of having to read the local scope, which likely contains method calls that may or may not modify that variable.

val and final have stronger meanings when your objects are immutable. True immutability makes reasoning far easier than just referential immutability.


> At least in Java, non-final variables can't be used inside anonymous inner classes.

Aren't those members/fields not variables? If so, then those are effectively global not local, so that's a completely different story – I'm talking strictly about local variables.

> True immutability makes reasoning far easier than just referential immutability.

Yep, immutable types and constant global bindings are great.


No, it applies for local variables as well: http://stackoverflow.com/questions/7423028/java-local-variab...

I still don't understand why you consider having a compiler-enforced restriction on mutation worse than letting readers figure out what was the developer's intent.

In Java, the only "downside" is having to add "final" as a modifier, which is negligible.

In Scala, the alternative is to declare that variable as "var" instead of "val". When would you ever choose var over val if your object isn't supposed to mutate?


That's just a weird wart of Java – not allowing anonymous inner classes to close over non-final variables was just a cheat to avoid having to implement proper closures; I have no idea what the technical impediments to doing so were when that decision was made, but plenty of languages, including Scala, have real closures.

> In Scala, the alternative is to declare that variable as "var" instead of "val". When would you ever choose var over val if your object isn't supposed to mutate?

It's an extra keyword, an extra complication in the language – one more binary choice to multiply with all the other options. It would be nice to get rid of the distinction altogether.


In Scala, there are both mutable and immutable data structures. Immutable data structures are preferred, however there are some cases in which a dash of mutability can simplify the code, especially in cases where Java inter-op is a must.


When it comes to helping a programmer understand code, every little bit helps. Humans are not good at parsing and keeping complex state in our minds, computers are. The less clutter I need to keep track of, the more interesting stuff about the code I can concern myself with.

As for marking local variable bindings as non-changing, I think it is tremendously helpful. In the (mostly Java) code base I work in daily we use this throughout. The net result is that I can just assume that property for everything, and whenever I see a variable not marked as non-changing I immediately know that something less than obvious is happening.

Given the above, I am naturally a big fan of making non-changing variable bindings (final/cons/val/...) the default and updatable variable bindings the case that should be marked. I would also like to work in a language where immutability of not just the variable binding but also the values themselves was better handled by the language.


In Scala, most variables should be val (i.e. constant) from a design perspective. That is, it is better, in Scala, to write code that does not have changing variable. Thus, using val instead of var is simply a check on the code, much in the same way that static typing provides a benefit over dynamic typing.


> much in the same way that static typing provides a benefit over dynamic typing.

A non-trivial number of people would dispute that ;-)


I don't think so, actually: in all the heated discussions I've had with people on the subject of static / dynamic typing, everybody agreed that static typing had significant benefits. What people don't agree on is whether these benefits are worth the cost.

It's hard to argue in good faith that having the compiler catch mistakes rather than finding about them at runtime is a bad thing. It's perfectly possible to argue that it's not worth the perceived development speed slowdown.


Keep in mind that all of this is just my opinion. I'm not going to append "IMHO" to each sentence, as to save the reader the tedium of reading it. I'm not saying that I'm correct or that people should agree with me.

I would go so far as to say that I think overly simplistic static type systems don't have much benefit. C's static typing drives me crazy, as there's almost nothing of use that I can express with it. It's the same with Go; I almost never pass an Int when I meant to pass a Bool. In exchange for thoroughly unhelpful type errors I now have to jump through flaming hoops to parse JSON.

It ends up being a bit like JavaScript or Python where both languages lack the ability to specify that something is truly private (though in JS you can use closures to hide things). You generally just use a naming convention to mark a thing as private, and hopefully people have the decency to respect that. It's like that with types in dynamic languages; I can express pretty complex relationships with types and keep the whole thing in my head with out many problems.

That said, languages with powerful type systems like Scala and Haskell are thoroughly worth the effort. I can express almost anything with these type systems, usually with a minimum of fuss. They can protect me from the dreaded NPE, and that's a bug I encounter quite often. They can help me write simpler code that deals with complex shapes of data with their support for pattern matching and TCO. This one is more Haskell related, but the guarantee that everything is immutable and lazy makes it possible for the compiler to do some insanely impressive optimizations.

Scala, Haskell, and Rust have taken a dyed-in-the-wool lover of dynamic languages and made a convert of me. They finally followed through on the promises of safety and productivity that other languages failed to deliver on.

In closing, I'll repeat one last time that all of these are merely the opinions of an insufferable neck beard (me). Even if we disagree, I'm sure you're a very nice person, and I approve of you using whatever languages and tools make you happy and productive.


I can't help but wonder whether you're that circumspect with everyone or if I come off as crazy-kill-you-you-phillistine and need to work on my communication skills?

Aside from the fact that I've never felt scarier, I agree entirely with every single point you just made and thank you for qualifying my broad generalisation.


No, not in the slightest, though you've made me laugh like a maniac in front of my co-workers. So there's that, you fiend.

It was more of a general butt-covering sort of thing. People like to take offense to things on the internet.


I agree with this. I also somethings think that I use the type system the most when I am refactoring/redesigning code and at that time I might be sending a bool instead of an int as someone wrote which is being caught by any good type system. Regarding the cost I think an optional type system, like in Dart, is intresting. You can do some prototyping or quick coding and then add types when you have some working code in order to develop fast, or you can use types all the time in order to be correct.


Purely from a reader's perspective, yes, an IDE can probably parse and highlight mutable variables automatically.

But from a writer's, modifier's or refactorer's perspective, what counts is the intent. Was a particular local variable meant to be mutable or immutable? Everytime I write a line of code, I need to watch out whether I mutated a variable which was not meant to be mutated. Or even the case where I myself mutate it unintentionally (by a typo, for example).

In a non-trivial project having a code-base with 100K lines of code, the time and effort spent in this manual analysis can be an overhead that might be well worth avoiding.


> It's easy for a parser or a person to scan the local scope and see if a variable is ever possibly mutated or not.

"what the parser figured out" != "what the author intended"

> this is a straightforward syntactic property

Not for the reader.


No, seriously, it's easy:

Is there exactly one assignment location that's not in a loop or a conditional?

yes => constant ; no => non-constant

This is neither hard nor unintuitive.


So you are recommending to create a special case just for declarations in local scope?

So "var" in global places means "variable", but "var" in local places means "variable or value"?


I'm not recommending anything. I'm wondering what the point of declaring something that's obvious from a simple syntactic analysis is. The author of this post makes a big deal of it and I don't see why it's useful. If the motivation is that constness is the right default in global scope and you want to make local and global scope more similar (even though they are still radically different), that's cool, but then don't make it out like local variables defaulting to const is the best thing ever invented.




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

Search: