Hygienic startup file


#1

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


#2

Joel VanderWerf removed_email_address@domain.invalid wrote/schrieb
removed_email_address@domain.invalid:

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

I can. That’s it, thanks!

Thomas


#3

Thomas H. wrote:

# 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


#4

On 23.04.2009 16:50, Thomas H. wrote:

Joel VanderWerf removed_email_address@domain.invalid wrote/schrieb removed_email_address@domain.invalid:

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

I can. That’s it, thanks!

Now you made me curious: why?

robert


#5

2009/4/24 Thomas H. removed_email_address@domain.invalid:

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


#6

Robert K. removed_email_address@domain.invalid wrote/schrieb
removed_email_address@domain.invalid:

On 23.04.2009 16:50, Thomas H. wrote:

Joel VanderWerf removed_email_address@domain.invalid wrote/schrieb removed_email_address@domain.invalid:

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

I can. That’s it, thanks!

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


#7

Robert K. removed_email_address@domain.invalid wrote/schrieb
removed_email_address@domain.invalid:

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


#8

Robert K. removed_email_address@domain.invalid wrote/schrieb
removed_email_address@domain.invalid:

EOF
Test is 123
Is there TEST?
-:6:in `’: 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


#9

On 25.04.2009 00:04, Thomas H. wrote:

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).

  1. 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 `’: uninitialized constant TEST (NameError)

robert@fussel ~
$

Kind regards

robert