hygienic startup file

T

Thomas Hafner

Hello,

a startup file to be loaded by RUBYOPT should have minimal side
effects. I guess, this pattern will do it:

class << Object.new
FOO = ... # will not override FOO if defined before
BAR = ... # will introduce BAR intermediately
...
# Use the constants above to do some wanted side effect on an
# object hold by a global variable, e.g. $LOAD_PATH :
$:.unshift(FOO, ...)
end
# no more BAR visible here

Is there a canonical way to achive this kind of hygiene?

Regards
Thomas
 
J

Joel VanderWerf

Thomas said:
Hello,

a startup file to be loaded by RUBYOPT should have minimal side
effects. I guess, this pattern will do it:

class << Object.new
FOO = ... # will not override FOO if defined before
BAR = ... # will introduce BAR intermediately
...
# Use the constants above to do some wanted side effect on an
# object hold by a global variable, e.g. $LOAD_PATH :
$:.unshift(FOO, ...)
end
# no more BAR visible here

Is there a canonical way to achive this kind of hygiene?

Regards
Thomas

Can't you use local variables to do the same thing?

foo = ...
$:.unshift foo
 
T

Thomas Hafner

Robert Klemme said:
Now you made me curious: why?

I guess that using local variables is not exactly the same thing like
class constants, but it's close enough that I don't (yet) notice the
difference when writing Ruby programs which load that startup file:

Neither are the variables from outside visible to the loaded startup
file, nor are local variables of the startup file visible from
outside. (That wasn't the case for uppercase names (constants!), and
so I had to enclose them in a dummy class - or whatever - do you know
a simpler solution to hide constants, BTW?)

Regards
Thomas
 
R

Robert Klemme

2009/4/24 Thomas Hafner said:
I guess that using local variables is not exactly the same thing like
class constants,

Of course it's not the same, but it always depends on the use case.
but it's close enough that I don't (yet) notice the
difference when writing Ruby programs which load that startup file:

Does this mean you switched to local variables?
Neither are the variables from outside visible to the loaded startup
file, nor are local variables of the startup file visible from
outside. (That wasn't the case for uppercase names (constants!), and
so I had to enclose them in a dummy class - or whatever - do you know
a simpler solution to hide constants, BTW?)

The question is: why do you need constants if you want to hide them?
Now it is even less clear to me what you want. All I've understood is
that you want to require a file (even if it's autorequired) and make
sure that particular information does not leak. OTOH I am sure you
want some information to leak so why don't you use constants for the
things (classes, modules) that need to be known outside and use local
variables for the rest?

Cheers

robert
 
T

Thomas Hafner

Robert Klemme said:
The question is: why do you need constants if you want to hide them?

First I defined constants rather than variables simply because each of
them actually is constant rather than variable: the value never
changes after assignment. In C++ I would add a const qualifier to the
local variables, e.g. to prevent from unintentionally overriding it.
In Haskell ther's no need for a const keyword, because all definitions
are immutable per se, which is regarded a feature in this purely
functional programming language.

But in Ruby there are no local constants analogical to local
variables, so when I simply define constants I unintentionally export
them, too. (Freeze is no option, because it freezes the object hold by
the variable, not the variable itself.)

Every alternative has its own tradeoff:
1. If I define simple constants, I pollute the namespace of the
loading code.
2. If I define constants within class << Object.new, the code is
somehow ugly.
3. If I define local variables, I don't benefit from the fact that
they are actually constant.

So currently alternative #3 is best for me, but if somebody shows me a
way to make #2 less ugly (get away from class << Object.new), that
would probably my favorite.

Regards
Thomas
 
R

Robert Klemme

First I defined constants rather than variables simply because each of
them actually is constant rather than variable: the value never
changes after assignment. In C++ I would add a const qualifier to the
local variables, e.g. to prevent from unintentionally overriding it.
In Haskell ther's no need for a const keyword, because all definitions
are immutable per se, which is regarded a feature in this purely
functional programming language.

Keep in mind that Ruby constants are not really constant:

robert@fussel ~
$ ruby19 -e 'X=1;puts X;X=2;puts X'
1
-e:1: warning: already initialized constant X
2

Generally, Ruby is less strict with these things ("private" is another
example).
But in Ruby there are no local constants analogical to local
variables, so when I simply define constants I unintentionally export
them, too. (Freeze is no option, because it freezes the object hold by
the variable, not the variable itself.)

Every alternative has its own tradeoff:
1. If I define simple constants, I pollute the namespace of the
loading code.
2. If I define constants within class << Object.new, the code is
somehow ugly.

This is also a kind of inappropriate solution because you create an
instance just to get at its singleton class. This is not needed (see
below).
3. If I define local variables, I don't benefit from the fact that
they are actually constant.

So currently alternative #3 is best for me, but if somebody shows me a
way to make #2 less ugly (get away from class << Object.new), that
would probably my favorite.

You can use an anonymous module for this:

robert@fussel ~
$ ruby19 <<EOF
Module.new do
TEST = 123
puts "Test is #{TEST}"
end
puts "Is there TEST?"
puts TEST
EOF
Test is 123
Is there TEST?
-:6:in `<main>': uninitialized constant TEST (NameError)

robert@fussel ~
$

Kind regards

robert
 
T

Thomas Hafner

Robert Klemme said:
You can use an anonymous module for this:

robert@fussel ~
$ ruby19 <<EOF
Test is 123
Is there TEST?
-:6:in `<main>': uninitialized constant TEST (NameError)

Interesting: for ruby1.8 there's still TEST. If I replace Module.new
by Class.new, it's OK. Seems that I need an anonymous class for ruby
1.8.

Regards
Thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,787
Messages
2,569,631
Members
45,338
Latest member
41Pearline46

Latest Threads

Top