Hacker News new | ask | show | jobs
by derefr 1119 days ago
> So while sigils have a lot of company in this, they are also a flat zero for me on this scale. Never ever missed them. I did a decade+ of Perl as my main language, so it's not for lack of exposure.

I tend to miss one specific sigil (or pair of sigils): the @ and @@ sigils in Ruby, that mean "instance variable" and "class variable" respectively. Having identifier shadowing between stack-locals, and what Java would call "members" and "statics", be literally impossible, is just so nice. Especially when you get it "for free" in terms of verbosity, rather than needing to type `self.class.` or something.

I also really quite interned-string-literal : sigils in Ruby/Elixir — though I'd be equally fine with the Prolog/Erlang approach of barewords being symbols and identifiers needing to be capitalized. As long as there's some concise syntax for interned strings, especially in the context of dictionary keys. Because otherwise people just won't use them, even when they're there in the language. (See: Java, Python, ECMA6.)

Speaking of Elixir, the "universal sigil" ~ is kind of amazing. Define a macro sigil_h/2, and you can suddenly write ~h/foo/bar (or ~h[foo]bar, or whatever other delimiter works to best avoid the need for escaping), and foo and bar will be passed to sigil_h/2 as un-evaluated AST nodes to do with as you please. The language gives you ~w by default (which works like Ruby %w); but more interestingly, Regex literals in Elixir are just sigil_r.

3 comments

> I tend to miss one specific sigil (or pair of sigils): the @ and @@ sigils in Ruby, that mean "instance variable" and "class variable" respectively. Having identifier shadowing between stack-locals, and what Java would call "members" and "statics", be literally impossible, is just so nice. Especially when you get it "for free" in terms of verbosity, rather than needing to type `self.class.` or something.

When I went from C++ to Python, the explicit "self" felt weird but over time, I felt it was much better. This became a lot more obvious in Rust. In C++ you get an implicit `this` variable and you get weird trailing keywords on functions to modify the `this` variable. Granted, these kinds of use cases won't be needed in every language. However, I also feel like sigils for this would be less understandable for someone unfamiliar with the language than explicit `self`. Something I judge a language on is how easy is the code to casually maintain by a group that is trying to get other stuff done.

The thing about Ruby is that it has uniform syntax — a.b for any a+b mean "send a message :b to a." So `self.foo` (and `self.foo = bar`, too!) are possible to write, but these are always interpreted as message sends (to the :foo and :foo= methods, respectively), not as direct field accesses. The "syntax-ness" of @ and @@ show are that you're specifically breaking out of† the paradigm of "everything is a message send", to instead "just" access a field. It's what makes this make sense:

    def foo # define a getter method
      @foo # in terms of a field access
    end
How would you write that, if the field access was spelled `self.foo`? The language wouldn't be able to tell that you're not just recursively calling the getter!

---

† Though, technically, you're not breaking out of the paradigm; @foo is short for self.instance_variable_get(:@foo). It's message-sends all the way down, until you hit natively-implemented methods.

> How would you write that, if the field access was spelled `self.foo`? The language wouldn't be able to tell that you're not just recursively calling the getter!

You can require parentheses for method calls put methods and fields in separate namespaces.

https://play.rust-lang.org/?version=stable&mode=debug&editio...

Elixir supports paren-free calls but the default linter and formatter won't let you use them except for a few whitelisted DSLs. I've never missed not having them.

In languages that require parens for method calls, not using them usually gets you a method handle. Which is still in conflict with a field reference — usually because methods are just function-pointer-typed static fields.
That's why I said "you can" rather than "you must". And linked to an example that of a language with the property I described.
As someone who infrequently had to touch Ruby code, this was maddening. Years later, I only now am finding out what was going wrong and a better sense of what search terms to use.

As I said I'm a big propoenent in languages being approachable for those infrequent one-off cases. I've been burned by the challenge of updating the "handful" of Perl and Ruby scripts (and Perl was my first language). This is why I advocate against Lua and 1-indexing when the target audience is programmers and it isn't a "primary" language.

I also have to touch Ruby code from time to time, so when I found out I don't quite understand what "@" and "@@" mean (other parts, even blocks, were kinda more or less apparent), I... went and read the docs. Took me an hour or two but now I know what "@" and "@@" mean and actually think they're a pretty ingenious solution.
I explicit this.thing in C# as well. It started from inheriting some coding standards / projects whose designers came straight from C and didn't do the idiomatic _variable thing for instance variables.

Now it's quite an entrenched habit and at this stage I'd prefer if the implicit access wasn't possible.

Agree on Ruby ivar/cvar sigils. We ran into some nasty variable shadowing, especially with autowiring frameworks, in big Java projects over the years.
Yes, those are handy. I don't much care for all the other ones in Ruby. Maybe the regexp one.