Hacker News new | ask | show | jobs
by xiaq 4156 days ago
var is for declaration, set for assignment. This is an important contrast that some dynamic languages miss; ironically JavaScript got it right. Contrast this

    var $x = "foo"; if $true { set $x = "bar" }; echo $x # outputs "bar"
with

    var $x = "foo"; if $true { var $x = "bar" }; echo $x # outputs "foo"
The declaration/assignment contrast is very important when it comes to closures (and there are closures in elvish). In python 2, for instance, there is no way (!) to assign to outer variables in closures since `=` declares and assigns at the same time in a `def` block.

There are no variable expansions, but strings are concatenated implicitly when they run together. In sh:

    echo "hello $name, welcome!"
In elvish:

    echo "hello "$name", welcome!"
Implicit concatenation can read a bit weird at first, but it's actually conceptually much simpler and only slightly more cumbersome than string interpolation. It also makes the syntax much simpler.
2 comments

JavaScript didn't really get it right:

  var a = 1;

  function four() {
    if (true) {
      var a = 4;
    }

    alert(a); // alerts '4', not the global value of '1'
  }
Also, if you omit 'var', the code is still legal (except in strict mode), and the variable winds up in the global scope, which is a recipe for disaster.

Still, it's nice that 'var' exists in JS at all. The idea that variable declarations are unnecessary noise and should be elided -- an idea that dates back at least to BASIC -- is, in my opinion, one of the worst seductive ideas in programming language design. Unless your language has only a single global scope (like BASIC), it always causes problems -- and we know that block scope is important for nontrivial programs.

Elvish sounds interesting; I will have to check it out.

I don't think we know that. We know some notion of lexical scope is valuable, but function only vs block scope seems like an issue of familiarity/style.
Okay, but that doesn't change my point that a single global scope is archaic, and for good reason.
So I see why you want var, but can't you just treat "x = 5" as "set x = 5"?

You can also remove the need for var (at the expense of no safety for typos) by prohibiting shadowing, like coffeescript does.

The need for `set` has to do with syntax. In shells the first word of a statement is always considered to be the command, so "x = 5" will not work - it reads "execute command 'x' with arguments '=' and '5'". The traditional solution is to treat the command as an assignment when it contains '=', so you write "x=5" and you are prohibited from adding any spaces, which I find aesthetically very unpleasant.

I was not aware of the CoffeeScript approach towards shadowing before. I will look into it, but it seems to be a very controversial design choice of CoffeeScript.

Re coffeescript and shadowing: I don't like it because I dislike the mismatch in semantics with JavaScript and am used to Python, but beyond that, I'm not sure it's wrong.

Re set: it would slightly complicate your grammar, but I don't think detecting "word space* = ..." would create any ambiguities.

Partially this issue is just about how much you value explicitness/regularity vs. concision.

@hyperpape we seem to have hit the critical level for flame war and now I cannot reply to you :) it's said I will be able to reply after some cooldown time, but here is my reply:

re "word space* = ...": should this echo an equal sign and $ip, or assign $ip to $echo?

    echo =$ip
You're right. I knew at some point I'd make a bad assumption based on my own (limited) forays into writing a shell language.

In my case, I'm treating "=" as not able to be included in an unquoted string literal, and I'm requiring variables to start with $.

So in my shell, this would be a syntax error.

    echo =$ip
This works.

    $echo = $ip
If you relaxed the variable naming idea, it would set echo to $ip, but that's probably a bad idea.
No this doesn't work either, unless you sacrifice the functionality of using variables as commands. Suppose $echo is equal to "echo", what is the most reasonable thing one would expect `$echo = $ip` to do?

Also consider the following snippet:

    : ${SSH:=ssh}
    $SSH $host1 'command1'
    $SSH $host2 'command2'
This has at least two use cases: 1) The user may direct the script use an ssh that is installed somewhere not in PATH by overriding SSH; 2) The user may supply extra flags to ssh by overriding SSH.

That is for the traditional shell part, which is still true in elvish (although due to stricter word splitting semantics use case 2 is different in elvish). Also since in elvish closures are first-class values, it's very intuitive to just call them directly:

    var $f = {|$x $who| echo "Hello, "$who"!" }
    $f = world # outputs "Hello, world!"
From the design perspective, it is possible to let `$echo = $ip` stand for assignment and still retain the ability to use variables as commands. If you give special meaning to "=" when it's the second word and alone and introduce a "call" command:

    var $f = {|$x $who| echo "Hello, "$who"!" }
    call $f = world # outputs "Hello, world!"
    $f = world      # assigns "world" to $f
But this introduces quite some ugliness to the language, and I decided that just requiring assignments to use "set" is the best solution.

A relevant note: Coming up with syntax for a shell language is actually very difficult due to the existence of bare words which greatly limit your inventory of potential operators. For instance one would very likely expect "echo user@example.com" to just echo "user@example.com", so if you give special semantics to "@" or "." it causes confusion and inconvenience. The only safe place you can introduce new semantics is the command, and this forces the language to have a prefix structure. If this reminds you of Lisp, you are correct - due to lack of infix operators lisp has very few restrictions on variable names; but the situation in shell languages is the opposite: due to the liberal use of bare words it is very difficult to introduce new infix operators to a shell language.

I agree with all that, and you're right about the syntax being difficult.

My one caveat you can have a little more freedom if you're willing to give up some of the patterns of existing shells, at the cost of unfamiliarity. Of course, you also need to be as expressive as shell so far as possible.

Anyway, "set" isn't a high cost to bear. I don't like it, but that's personal preference, and it clearly helps with the syntax of what you're doing.