Context
Perhaps I'm just use to C-esque styled languages but having a sigil in front of a variable (e.g. $VAR
) always strikes me as weird.
Question
Why do some languages such as Perl and shell scripting have sigils in front of the variable names?
I can see it making sense for older languages like Basic (1960s) where the interpreter might not be smart enough to know what type of variable we are referring to. Looking at C in the 1970s, we see that is all but gone. In the 1980s, shell and Perl appeared and use the sigil notation yet Tcl, Erlang and others like C++ don't. In the 1990s, we see Python and Ruby not having sigils at all. Perhaps they do exist, but I haven't seen a recently developed programming language use sigils. I have, however, seen language do other stuff such as decorators from python @staticmethod
that can look like sigils but is used in a different context.
I don't code a lot in Perl but for bash, printf
is a function and wrapped in a command substitution, $(printf ...)
creates sprintf from C. With both of these options, I don't see gains of say using "This ${magic}String"
over printf "This %sString" "$magic"
especially when strings get really long. Similarly, ${#STR}
is confusing, especially to newer programmers that don't know what that piece of code does, whereas len str
is easier to read. Perhaps I'm just nitpicking over something that doesn't matter and everyone just accepts and moves on.
2 Answers 2
In the 1990s, we see Python and Ruby not having sigils at all.
Ruby doesn't have sigils? Ruby is the king of sigils!
$
is a global or pseudo-global variable,@
is an instance variable,@@
is a class hierarchy variable, and- (not technically a sigil, but similar in spirit) an uppercase letter is a constant variable.
And in the two cases where there isn't a sigil, there is an ambiguity between variables and methods:
foo
is that a method call or a variable? Ruby says: both! If it has parsed (not executed) an assignment before, it assumes, it's local variable, otherwise it assumes, it's a method call. So:
foo # method call
if false
foo = 42 # it doesn't matter that this isn't executed, only parsed
end
foo # local variable
# => nil
# un-initialized local variables evaluate to nil
Okay, and what if I want to call a method named foo
now? Well, I need to make it clear to Ruby that I intend to call a method:
foo() # pass an argument list, only methods can take arguments
self.foo # provide an explicit receiver, however doesn't work for private methods
This poses another problem: if I have a function assigned to a variable, how do I call that function? I can't do it with foo()
, because that calls a method named foo
, I have to say foo.()
.
For constants, the situation is similar. Foo
is always interpreted as a constant, in order to treat it as a method call, you have to say Foo()
or self.Foo
.
In Python, this ambiguity is resolved by always requiring an explicit receiver for anything which isn't a variable, and always requiring parentheses for calls. So, a local variable is always foo
, a method call is always self.foo()
, and calling a function stored in a local variable is always foo()
. An instance variable is always self.foo
.
ECMAScript solves it by having a single namespace for functions and variables, so that it is impossible to have both a function and a variable named foo
:
let foo = 42;
function foo() {};
// TypeError: Identifier 'foo' has already been declared
-
I guess I should use RUby a bit more and learn about that.unsignedzero– unsignedzero2016年03月24日 19:38:19 +00:00Commented Mar 24, 2016 at 19:38
In shell, where you have shell scripts, with an environment that can be manipulated by the caller of the script, it's really really useful if you can distinguish between "this is a variable reference" and "this is text" without having to consult the environment.
If any "defined variable" would be substituted for its value, the following would not be safe in a shell script:
ls /tmp/*
Because if you wanted that to become harmful, all you would need would be to do the following:
ls=rm
export ls
So having some sort of distinct signal saying "yes, this is fetching the value of a variable" is very useful.
Perl (probably) got this from shell, but extended it to use various prefix symbols to denote data types, so $foo
is a scalar variable, but @foo
is an array variable.
-
Even more evil:
ls=rm; tmp="/";
Jörg W Mittag– Jörg W Mittag2016年03月24日 11:50:45 +00:00Commented Mar 24, 2016 at 11:50 -
I don't believe this is one of the reasons variables are prepended with "$". Simply because you CAN replace commands with "alias". Example "alias ls=rm".user161778– user1617782016年03月28日 03:18:40 +00:00Commented Mar 28, 2016 at 3:18
-
@user161778: Note that an alias is NOT inherited through the normal environment (thus the need to define them in .bashrc).Vatine– Vatine2016年03月29日 16:02:12 +00:00Commented Mar 29, 2016 at 16:02
Explore related questions
See similar questions with these tags.
foobar
is a variable or the name of afile
, particularly in the case where both a variable and a file of that name exists?