I often use the ||= idiom in ruby for late initialization. But was recently looking for an idiom that would allow me to overwrite a variable if the right side is defined without repeating myself.
I have used the following:
var = val if val
but I have to repeat val and that violates DRY. I thought maybe &&= would work, but did not
I often use the ||= idiom in ruby for late initialization. But was
recently looking for an idiom that would allow me to overwrite a
variable if the right side is defined without repeating myself.
I have used the following:
var = val if val
but I have to repeat val and that violates DRY.
$ ruby -e 'a = b if b'
-e:1: undefined local variable or method `b' for main:Object
(NameError)
I thought maybe &&= would work, but did not
var &&= val
That only works if var and val are non-nil.
Any ideas out there?
I'm not sure it's possible, but it might depend on what state you want
to leave things in under what conditions. Even if you do this:
var = val if defined?(val)
var ends up being nil if val is *not* defined -- so that's
indistinguishable from the case where val exists and is nil. If it's
OK for var to be nil, then that would be OK, otherwise not.
I often use the ||= idiom in ruby for late initialization. But was recently looking for an idiom that would allow me to overwrite a variable if the right side is defined without repeating myself.
I have used the following:
var = val if val
but I have to repeat val and that violates DRY. [...]
Any ideas out there?
require 'binding_of_caller'
def and_set(name, value)
return if value.nil?
Binding.of_caller do |context|
eval("#{name} = ObjectSpace._id2ref(#{value.id})", context)
end
end
and_set(:var, val)
Not sure if you were looking for this kind of solution though.
Which might have worked in future Ruby, but alas no. But then what about
simple transactions? Isn't there a lib for something like:
transaction(:var) do
(var = val) ? commit : rollback
end
Just some wild guesses.
T.
···
On Tuesday 28 September 2004 04:29 pm, stevetuckner wrote:
I often use the ||= idiom in ruby for late initialization. But was
recently looking for an idiom that would allow me to overwrite a
variable if the right side is defined without repeating myself.
I have used the following:
var = val if val
but I have to repeat val and that violates DRY. I thought maybe &&=
would work, but did not
> I often use the ||= idiom in ruby for late initialization. But was
> recently looking for an idiom that would allow me to overwrite a
> variable if the right side is defined without repeating myself.
>
> I have used the following:
>
> var = val if val
>
> but I have to repeat val and that violates DRY.
$ ruby -e 'a = b if b'
···
On Wed, Sep 29, 2004 at 05:37:21AM +0900, David A. Black wrote:
On Wed, 29 Sep 2004, stevetuckner wrote:
===
a
-e:1: undefined local variable or method `b' for main:Object
(NameError)
--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com
def and_set(name, value)
return if value.nil?
Binding.of_caller do |context|
eval("#{name} = ObjectSpace._id2ref(#{value.id})", context)
end
end
and_set(:var, val)
Not sure if you were looking for this kind of solution though.
It probably does the trick (though I can't understand the binding_of_caller without more study), but was quite a bit more heavyweight than I was looking for. Thanks for trying...
$ ruby -e 'a = b if b'
-e:1: undefined local variable or method `b' for main:Object
(NameError)
Perhaps I should clarify how I was using this. Lets say I have a variable with a default value and I want to overwrite it with something else as long as it is non-nil.
a = "default"
a = foo.value if foo.value
I just wanted to see if there was a simple way to avoid the double foo.value that I was missing. Thanks for all your responses.
On Wed, Sep 29, 2004 at 05:37:21AM +0900, David A. Black wrote:
> Hi --
>
> On Wed, 29 Sep 2004, stevetuckner wrote:
>
> > I often use the ||= idiom in ruby for late initialization. But was
> > recently looking for an idiom that would allow me to overwrite a
> > variable if the right side is defined without repeating myself.
> >
> > I have used the following:
> >
> > var = val if val
> >
> > but I have to repeat val and that violates DRY.
>
> $ ruby -e 'a = b if b'
===
a
I was reading up this thread (I've been in meetings & working for
the past 8 hrs or so, and thus neglecting my duties as a netizen)
wondering if anyone had suggested this yet. Will I be the one to post
it? Will I?
*sigh*
I will not that (in the original poster's terms), this is
var = val || var
which still repeats (but the computationally cheap var instead of the
presumably costly val). There may be an idiom that avoids even that,
but I'll be darned if I know what it is.
-- MarkusQ
P.S. In Icon (IIRC) you can write either
var \= val
or
var /= val
one of which effectively does
var ||= val
and the other
var = val || var
but the semantics of icon are sufficiently different from ruby to make
this only an approximate analogy.
···
On Tue, 2004-09-28 at 21:30, Gavin Sinclair wrote:
Steve Tuckner wrote:
> a = "default"
> a = foo.value if foo.value
>
> I just wanted to see if there was a simple way to avoid the double
> foo.value that I was missing. Thanks for all your responses.
I will not that (in the original poster's terms), this is
var = val || var
or
a = foo.value || a
which more clearly shows the value (!) of this construct. Smart.
Thinking about my own code, I tend to write
var = val unless val.nil?
which is even more verbose, but seems a bit clearer, and works for the case
where val=false. However I end up assigning to a temporary variable 'val' in
the case of a complex expression. Maybe I'll adopt your pattern instead,
although I think it would leave some people scratching their heads at first.
There is the more general case of
if some.complex.expression
... do something with some.complex.expression
end
which I typically write as
if (val = some.complex.expression)
... do something with val
end
This does suggest some other solutions:
a = tmp if tmp = foo.value ## fails - first tmp is treated as method
if tmp = foo.value; a = tmp; end
(tmp = foo.value) && (a = tmp)
Icky though. It might be nice if the value of the condition evaluated in an
'if', or the LHS of && or ?:, were somehow available to the body/RHS. I
can't think how it would work nicely: