Case of sub! not working

Hi,

Here’s an interesting phenomenon:

[ianmacd@baghdad]$ irb
irb(main):001:0> ENV[‘PATH’]
=> "/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin:/usr/kerberos/bin"
irb(main):002:0> ENV[‘PATH’].sub!(%r(:/usr/kerberos/bin), ‘’)
=> "/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin"
irb(main):003:0> ENV[‘PATH’]
=> "/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin:/usr/kerberos/bin"
irb(main):004:0> puts VERSION
1.8.0
=> nil

Why doesn’t the sub! work in line 002? It returns the correct answer,
but ENV[‘PATH’] is not modified in-place. I’ve verified that the
behaviour is the same in 1.6, too.

Ian

···


Ian Macdonald | If little green men land in your back yard,
System Administrator | hide any little green women you’ve got in
ian@caliban.org | the house. – Mike Harding, “The Armchair
http://www.caliban.org | Anarchist’s Almanac”
>

Ian Macdonald wrote:

Hi,

Here’s an interesting phenomenon:

[ianmacd@baghdad]$ irb
irb(main):001:0> ENV[‘PATH’]
=> “/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin:/usr/kerberos/bin”
irb(main):002:0> ENV[‘PATH’].sub!(%r(:/usr/kerberos/bin), ‘’)
=> “/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin”
irb(main):003:0> ENV[‘PATH’]
=> “/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin:/usr/kerberos/bin”
irb(main):004:0> puts VERSION
1.8.0
=> nil

Why doesn’t the sub! work in line 002? It returns the correct answer,
but ENV[‘PATH’] is not modified in-place. I’ve verified that the
behaviour is the same in 1.6, too.

ENV is not exactly a Hash, but a singleton that behaves kinda like one.
Apparently, one difference is that ENV[key] returns a copy of the value.
(In hash.c, you can verify this by seeing that rb_f_getenv() calls
rb_str_new2 or rb_tainted_str_new2 to generate the return value.)

So I guess you have to do something like

ENV[‘PATH’] = ENV[‘PATH’].sub(…)

Ian Macdonald wrote:

Hi,

Moin!

irb(main):002:0> ENV[‘PATH’].sub!(%r(:/usr/kerberos/bin), ‘’)
=> “/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin”
irb(main):003:0> ENV[‘PATH’]
=> “/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin:/usr/kerberos/bin”

Why doesn’t the sub! work in line 002? It returns the correct answer,
but ENV[‘PATH’] is not modified in-place.

You now know why this isn’t the case, but I chose to try making it
work anyway. I attached a small hack which changes the original ENV
and ENV= so that they return a proxy to the real contents which
changes ENV when it is changed.

This allows you to do this:

ENV[‘foo’] = “hello world” # => “hello world”
ENV[‘foo’].replace(“whatever”).reverse!.gsub!(/[aeiou]/, “")
# => "r
vthw”
ENV[‘foo’] # => “rvt*hw”

I didn’t really test this in detail so it might have small bugs or
break your Ruby into tiny little shivers.

Regards,
flgr

proxied_env.rb (798 Bytes)

Ian Macdonald wrote:

Here’s an interesting phenomenon:

[ianmacd@baghdad]$ irb
irb(main):001:0> ENV[‘PATH’]
=> “/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin:/usr/kerberos/bin”
irb(main):002:0> ENV[‘PATH’].sub!(%r(:/usr/kerberos/bin), ‘’)
=> “/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin”
irb(main):003:0> ENV[‘PATH’]
=> “/usr/bin:/bin:/usr/X11R6/bin:/usr/pubsw/bin:/usr/kerberos/bin”
irb(main):004:0> puts VERSION
1.8.0
=> nil

Why doesn’t the sub! work in line 002? It returns the correct answer,
but ENV[‘PATH’] is not modified in-place. I’ve verified that the
behaviour is the same in 1.6, too.

ENV is not exactly a Hash, but a singleton that behaves kinda like one.
Apparently, one difference is that ENV[key] returns a copy of the value.
(In hash.c, you can verify this by seeing that rb_f_getenv() calls
rb_str_new2 or rb_tainted_str_new2 to generate the return value.)

Thanks for the explanation. This definitely violates the principle of
least surprise, however, and I consider it a bug. At the very least, it
should go into the documentation, including the FAQ.

So I guess you have to do something like

ENV[‘PATH’] = ENV[‘PATH’].sub(…)

Yes, that’s what I came up with, too.

Ian

···

On Tue 03 Jun 2003 at 10:21:43 +0900, Joel VanderWerf wrote:

Ian Macdonald | Harrisberger’s Fourth Law of the Lab:
System Administrator | Experience is directly proportional to the
ian@caliban.org | amount of equipment ruined.
http://www.caliban.org |
>

A surprise but not a bug. Things that interact with
the outside world sometimes work that way in Ruby.
A similar example is cgi.params which is hash-like
but is not a hash. (Of course, it’s changed somewhat
since I started playing with it.)

Hal

···

----- Original Message -----
From: “Ian Macdonald” ian@caliban.org
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Monday, June 02, 2003 10:21 PM
Subject: Re: case of sub! not working

Thanks for the explanation. This definitely violates the principle of
least surprise, however, and I consider it a bug. At the very least, it
should go into the documentation, including the FAQ.

Hi,

ENV is not exactly a Hash, but a singleton that behaves kinda like one.
Apparently, one difference is that ENV[key] returns a copy of the value.
(In hash.c, you can verify this by seeing that rb_f_getenv() calls
rb_str_new2 or rb_tainted_str_new2 to generate the return value.)

Thanks for the explanation. This definitely violates the principle of
least surprise, however, and I consider it a bug. At the very least, it
should go into the documentation, including the FAQ.

Never say that. You had two assumptions

  • sub! to modify the receiver in-place

  • when you modify the string from ENV in-place, the value of the
    environment variable changes automagically.

The former assumption is valid, the latter is not. And it costs very
much to satisfy your expectation.

But I agree with putting it in the FAQ, for people fall into the same
trap.

						matz.
···

In message “Re: case of sub! not working” on 03/06/03, Ian Macdonald ian@caliban.org writes:

Thanks for the explanation. This definitely violates the principle
of
least surprise, however, and I consider it a bug. At the very
least, it
should go into the documentation, including the FAQ.

Can someone mention why this is like it is? (ENV keys are copies
so modifications are lost.)

···

Do you Yahoo!?
Yahoo! Calendar - Free online calendar with sync to Outlook™.
http://calendar.yahoo.com

Hi,

ENV is not exactly a Hash, but a singleton that behaves kinda like one.
Apparently, one difference is that ENV[key] returns a copy of the
value.
(In hash.c, you can verify this by seeing that rb_f_getenv() calls
rb_str_new2 or rb_tainted_str_new2 to generate the return value.)

Thanks for the explanation. This definitely violates the principle of
least surprise, however, and I consider it a bug. At the very least, it
should go into the documentation, including the FAQ.

Never say that. You had two assumptions

  • sub! to modify the receiver in-place

  • when you modify the string from ENV in-place, the value of the
    environment variable changes automagically.

The former assumption is valid, the latter is not. And it costs very
much to satisfy your expectation.

But I agree with putting it in the FAQ, for people fall into the same
trap.

how about making the interpreter running a $ENV.freeze at the beginning of
the program?
if the variable can’t be modified (somehow), it’d be more intuitive if it’s
read-only, or do i miss something?

emmanuel

···

In message “Re: case of sub! not working” > on 03/06/03, Ian Macdonald ian@caliban.org writes:

I’ll take a stab at it. I can’t promise that
what I say is correct.

The illusion of ENV being a simple hash is a
good one. But remember that when you get/set
environment variables, ultimately you are
calling getenv/setenv or some equivalent.

It’s one thing to do an ENV = y, as =
is a method invoked on ENV. We can trap the
change and call setenv.

But if ENV refers to a string, and I change
that string… then ENV itself hasn’t changed.
In fact, for an in-place change, even the
object id of the string hasn’t changed.

To accomplish something like ENV.sub! working
intuitively, we would have to monitor every
string object referenced by ENV and watch to see
when any of them was changed.

Perhaps possible but impractical and inefficient.

Hal

···

----- Original Message -----
From: “Michael Campbell” michael_s_campbell@yahoo.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Tuesday, June 03, 2003 8:15 AM
Subject: Re: case of sub! not working

Thanks for the explanation. This definitely violates the principle
of
least surprise, however, and I consider it a bug. At the very
least, it
should go into the documentation, including the FAQ.

Can someone mention why this is like it is? (ENV keys are copies
so modifications are lost.)

Emmanuel Touzery wrote:

how about making the interpreter running a $ENV.freeze at the beginning of
the program?
if the variable can’t be modified (somehow), it’d be more intuitive if it’s
read-only, or do i miss something?

ENV[‘foo’] = ‘bar’

p echo $foo

Hi,

···

In message “Re: case of sub! not working” on 03/06/03, “Emmanuel Touzery” emmanuel.touzery@wanadoo.fr writes:

how about making the interpreter running a $ENV.freeze at the beginning of
the program?

Do you mean freezing strings from ENV? Hmm, maybe.

						matz.

I’ll take a stab at it. I can’t promise that
what I say is correct.

I gotcha. Ruby is doing this to avoid having to track the actual
changes to the string (outside of changes to ENV), and/or dealing
with copy-on-write semantics.

Interesting; thanks.

···

Do you Yahoo!?
Yahoo! Calendar - Free online calendar with sync to Outlook™.
http://calendar.yahoo.com

Somebody suggested that strings returned by ENV# be frozen,
emphasizing that they can’t be changed. I like that idea, it
seems to get rid of any need to add an explanation of all
this to the FAQ.

Sam

···

I’ll take a stab at it. I can’t promise that
what I say is correct.

The illusion of ENV being a simple hash is a
good one. But remember that when you get/set
environment variables, ultimately you are
calling getenv/setenv or some equivalent.

It’s one thing to do an ENV = y, as =
is a method invoked on ENV. We can trap the
change and call setenv.

But if ENV refers to a string, and I change
that string… then ENV itself hasn’t changed.
In fact, for an in-place change, even the
object id of the string hasn’t changed.

To accomplish something like ENV.sub! working
intuitively, we would have to monitor every
string object referenced by ENV and watch to see
when any of them was changed.

Perhaps possible but impractical and inefficient.

Hal

Emmanuel Touzery wrote:

how about making the interpreter running a $ENV.freeze at the beginning
of
the program?
if the variable can’t be modified (somehow), it’d be more intuitive if
it’s
read-only, or do i miss something?

ENV[‘foo’] = ‘bar’

p echo $foo

wow, nice :O)

didn’t know that…

In my program, however, I would have been quite happy to have sub! just
modify the copy of ENV[‘PATH’] that it had made, as I wanted to modify
the path that would be used to find the location of a binary I was about
to open with popen. I wasn’t trying to modify the outside environment,
just that of my script and any of it children.

Ian

···

On Wed 04 Jun 2003 at 04:39:44 +0900, Michael Campbell wrote:

I’ll take a stab at it. I can’t promise that
what I say is correct.

I gotcha. Ruby is doing this to avoid having to track the actual
changes to the string (outside of changes to ENV), and/or dealing
with copy-on-write semantics.

Interesting; thanks.


Ian Macdonald | Breeding rabbits is a hare raising
System Administrator | experience.
ian@caliban.org |
http://www.caliban.org |
>

Yukihiro Matsumoto wrote:

how about making the interpreter running a $ENV.freeze at the beginning of
the program?

Do you mean freezing strings from ENV? Hmm, maybe.

don’t take this seriously…

what if ENV’s = doesn’t return strings, but string-like objects (or
instances of some subclass of String) that has a custom sub! (and all
other MODIFY! methods) containing setenv?

perhaps that could complete the hash-like illusion of ENV? :slight_smile:

···


dave

Saluton!

  • Emmanuel Touzery; 2003-06-03, 11:06 UTC:

ENV[‘foo’] = ‘bar’

p echo $foo

Let me add the result of the above code:

“bar\n”

wow, nice :O)

didn’t know that…

Please make sure you really do understand the whole issue:

$ ruby -e “ENV[‘foo’] = ‘bar’”; echo “‘$foo’”
‘’

The change is not persistent but limited to the environment your Ruby
script runs in - which is not the environment the script is started
from but discarded after run. As a result the above code only has
limited use. But that’s a Linux/Unix FAQ, no Ruby FAQ …

Gis,

Josef ‘Jupp’ Schugt

Which again needs the setenv() call to actually alter the value in the
environment. and it did modify the copy of ENV[‘PATH’] it made, but it
didn’t propagate it back to ENV :slight_smile:

ENV[‘bla’] = “banzai”
echo $bla # ← banzai\n
x=ENV[‘bla’].sub!(/banzai/, “ayaken”) # here the copy is modified, result => x
echo #{x} # ← ayaken\n <<- see, it did modify the copy
echo $bla # ← banzai\n <<- but no setenv() call.

-martin

···

On Wed, Jun 04, 2003 at 10:14:28AM +0900, Ian Macdonald wrote:

On Wed 04 Jun 2003 at 04:39:44 +0900, Michael Campbell wrote:

I’ll take a stab at it. I can’t promise that
what I say is correct.

I gotcha. Ruby is doing this to avoid having to track the actual
changes to the string (outside of changes to ENV), and/or dealing
with copy-on-write semantics.

Interesting; thanks.

In my program, however, I would have been quite happy to have sub! just
modify the copy of ENV[‘PATH’] that it had made, as I wanted to modify
the path that would be used to find the location of a binary I was about
to open with popen. I wasn’t trying to modify the outside environment,
just that of my script and any of it children.

Hi,

···

In message “Re: case of sub! not working” on 03/06/04, Ian Macdonald ian@caliban.org writes:

In my program, however, I would have been quite happy to have sub! just
modify the copy of ENV[‘PATH’] that it had made, as I wanted to modify
the path that would be used to find the location of a binary I was about
to open with popen. I wasn’t trying to modify the outside environment,
just that of my script and any of it children.

I understand what you feel, but still, environment variables are
entities in the operating system, the outside world from Ruby. You
were trying to modify the environment outside of Ruby, without
knowing. Read Hal’s explanation again in [ruby-talk:72787].

						matz.

David Garamond wrote:

what if ENV’s = doesn’t

sorry, i meant .

···


dave