Shortcut for add unless nil?

Hi,

Is was wondering if there's a Ruby idiom for adding variables that should be arrays but that may be nil, for example:

[1] + (a || [ ]) + (b || [ ]) + (c || [ ])

but that's a bit ugly IMO. I've had a look, but didn't see anything. I know I could use a fold or something similar, but I was wondering if there was something in the realms of ||= (i.e. nice, idiomatic shortcut) for this kind of thing?

Iain

You could do something like this (untested):

    [a, b, c, d].compact.reduce(:+)

though whether it is more clear is debatable. I think it reads fine if you're fluent.

El 24/03/2011, a les 19:36, Iain Barnett <iainspeed@gmail.com> va escriure:

···

Sent from my iPhone

Hi,

Is was wondering if there's a Ruby idiom for adding variables that should be arrays but that may be nil, for example:

[1] + (a || ) + (b || ) + (c || )

but that's a bit ugly IMO. I've had a look, but didn't see anything. I know I could use a fold or something similar, but I was wondering if there was something in the realms of ||= (i.e. nice, idiomatic shortcut) for this kind of thing?

Iain

The most idiomatic (and performant) shortcut is to not have the situation arise in the first place. Nil checks everywhere is generally a design smell. Push things up to whereever the defaults should be figured out... in railsy parlance:

    thingies = params[:thingies] ||

then later you never have to worry about it.

···

On Mar 24, 2011, at 11:36 , Iain Barnett wrote:

Hi,

Is was wondering if there's a Ruby idiom for adding variables that should be arrays but that may be nil, for example:

[1] + (a || ) + (b || ) + (c || )

but that's a bit ugly IMO. I've had a look, but didn't see anything. I know I could use a fold or something similar, but I was wondering if there was something in the realms of ||= (i.e. nice, idiomatic shortcut) for this kind of thing?

I agree to an extent, but even when you're defining defaults it would be nice:

    thingies = params[:thingies] ||
    wotsits = params[: wotsits] ||
    stuff = thingies + wotsits

isn't as nice as

    stuff = params[:thingies] +? params[:wotsits]

where +? is my new infix operator of choice for "add unless nil" :slight_smile: Sometimes I don't want the extra typing or to use extra locals that will only be used for that one line.

Iain

···

On 24 Mar 2011, at 22:45, Ryan Davis wrote:

The most idiomatic (and performant) shortcut is to not have the situation arise in the first place. Nil checks everywhere is generally a design smell. Push things up to whereever the defaults should be figured out... in railsy parlance:

   thingies = params[:thingies] ||

then later you never have to worry about it.

That works, thanks, though it starts to feel a bit messy if the array members aren't short vars and/or have square brackets too, as it gets pushed over several lines, and personally I dislike wrapping things with square brackets only to take them off just to use a fold. Whereas:

    a +
    [b,c,d] +
    e +
    f

would read a lot better in that kind of situation. If it could be done :slight_smile: The short vars in my example were due to typing laziness, I was thinking more for stuff like this:

    HEADERS = ENV["BLAH_BLAH"] + ENV["BLAH_BLAH_BLAH_BLAH"]

which begins to look unwieldy even with just two fairly long vars:
    
    HEADERS = [ENV["BLAH_BLAH"] + ENV["BLAH_BLAH_BLAH"]].compact.reduce(:+)

but

    HEADERS = ENV["BLAH_BLAH"] +
              ENV["BLAH_BLAH_BLAH"] +
              ENV["BLAH_BLAH_BLAH_BLAH"]

will remain clear even as the vars stack up.

Much appreciated though.

Iain

···

On 24 Mar 2011, at 18:53, Xavier Noria wrote:

You could do something like this (untested):

   [a, b, c, d].compact.reduce(:+)

though whether it is more clear is debatable. I think it reads fine if you're fluent.

What about

res = [a,b,c].inject([1]) {|r,x| x and r.concat(x) or r}

or

res = [a,b,c].inject([1]) {|r,x| x ? r.concat(x) : r}

or

res = [1]
[a,b,c].each {|x| x and res.concat x}

Kind regards

robert

···

On Fri, Mar 25, 2011 at 7:02 AM, Iain Barnett <iainspeed@gmail.com> wrote:

On 24 Mar 2011, at 18:53, Xavier Noria wrote:

You could do something like this (untested):

[a, b, c, d].compact.reduce(:+)

though whether it is more clear is debatable. I think it reads fine if you're fluent.

That works, thanks, though it starts to feel a bit messy if the array members aren't short vars and/or have square brackets too, as it gets pushed over several lines, and personally I dislike wrapping things with square brackets only to take them off just to use a fold. Whereas:

a +
[b,c,d] +
e +
f

would read a lot better in that kind of situation. If it could be done :slight_smile: The short vars in my example were due to typing laziness, I was thinking more for stuff like this:

HEADERS = ENV["BLAH_BLAH"] + ENV["BLAH_BLAH_BLAH_BLAH"]

which begins to look unwieldy even with just two fairly long vars:

HEADERS = [ENV["BLAH_BLAH"] + ENV["BLAH_BLAH_BLAH"]].compact.reduce(:+)

but

HEADERS = ENV["BLAH_BLAH"] +
ENV["BLAH_BLAH_BLAH"] +
ENV["BLAH_BLAH_BLAH_BLAH"]

will remain clear even as the vars stack up.

Much appreciated though.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Yeah. Well... I disagree. We really don't need extra magical syntax. I can almost guarantee you that this proposal would get rejected by ruby-core@, but you're free to ask.

···

On Mar 24, 2011, at 22:33 , Iain Barnett wrote:

On 24 Mar 2011, at 22:45, Ryan Davis wrote:

The most idiomatic (and performant) shortcut is to not have the situation arise in the first place. Nil checks everywhere is generally a design smell. Push things up to whereever the defaults should be figured out... in railsy parlance:

  thingies = params[:thingies] ||

then later you never have to worry about it.

I agree to an extent, but even when you're defining defaults it would be nice:

   thingies = params[:thingies] ||
   wotsits = params[: wotsits] ||
   stuff = thingies + wotsits

isn't as nice as

   stuff = params[:thingies] +? params[:wotsits]

where +? is my new infix operator of choice for "add unless nil" :slight_smile: Sometimes I don't want the extra typing or to use extra locals that will only be used for that one line.

I'd also wondered whether Iain Barnett really needed array + array2
rather than array.concat(array2), and wondered about something
similar:

class Array
  def concat_not_nil( *args )
    args.each { |arg| concat(arg) unless arg.nil? }
    self
  end
  def plus_not_nil( *args )
    new_ary = self.dup
    new_ary.concat_not_nil( *args )#
  end
end

···

On Fri, Mar 25, 2011 at 7:52 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

What about
...
res = [1]
[a,b,c].each {|x| x and res.concat x}

I really appreciate the responses, but if I apply them to the code that provoked the question for me, and my dislike of wrapping things in an array only to get access to a function or block (which also then removes the wrapper), and of creating locals for a single use, then I'm not so sure they work. As in, there are so many great shortcuts in Ruby that feel very natural too, that some kind of infix operator works well for args split over several lines due to their length.

I think this reads very easily, HEADERS is 3 env vars added up into one:

    HEADERS = ENV["BLAH_BLAH"] +
              ENV["BLAH_BLAH_BLAH"] +
              ENV["BLAH_BLAH_BLAH_BLAH"]

to this, which creates an array then destroys it, which kind of masks the intention:

    HEADERS = [
                ENV["BLAH_BLAH"],
                ENV["BLAH_BLAH_BLAH"],
                ENV["BLAH_BLAH_BLAH_BLAH"]
              ].inject([1]) {|r,x| x and r.concat(x) or r}

If I was going to use a fold or something similar then I would probably have done something like this, or used a ternary operator in a fold, (knowing the way I think):

    HEADERS = [
                ENV["BLAH_BLAH"],
                ENV["BLAH_BLAH_BLAH"],
                ENV["BLAH_BLAH_BLAH_BLAH"]
              ].reject{|x| x.nil? }.reduce(:+)

but compared to this it seems a bit creaky:

    HEADERS = ENV["BLAH_BLAH"] +?
              ENV["BLAH_BLAH_BLAH"] +?
              ENV["BLAH_BLAH_BLAH_BLAH"]

Is there a way to define infix operators in Ruby, as I quite like this one? :slight_smile:

Actually, looking at the code they'd be ENV["BLAH_BLAH"].split(":") as they were PATHs, but I'm not sure the inclusion adds anything to the examples.

Regards,
Iain

···

On 25 Mar 2011, at 14:32, Colin Bartlett wrote:

On Fri, Mar 25, 2011 at 7:52 AM, Robert Klemme > <shortcutter@googlemail.com> wrote:

What about
...
res = [1]
[a,b,c].each {|x| x and res.concat x}

I'd also wondered whether Iain Barnett really needed array + array2
rather than array.concat(array2), and wondered about something
similar:

class Array
def concat_not_nil( *args )
   args.each { |arg| concat(arg) unless arg.nil? }
   self
end
def plus_not_nil( *args )
   new_ary = self.dup
   new_ary.concat_not_nil( *args )#
end
end

What about
...
res = [1]
[a,b,c].each {|x| x and res.concat x}

I'd also wondered whether Iain Barnett really needed array + array2
rather than array.concat(array2), and wondered about something
similar:

class Array
def concat_not_nil( *args )
args.each { |arg| concat(arg) unless arg.nil? }
self
end
def plus_not_nil( *args )
new_ary = self.dup
new_ary.concat_not_nil( *args )#
end
end

I really appreciate the responses, but if I apply them to the code that provoked the question for me, and my dislike of wrapping things in an array only to get access to a function or block (which also then removes the wrapper), and of creating locals for a single use, then I'm not so sure they work.

Maybe you should reduce your requirements...

As in, there are so many great shortcuts in Ruby that feel very natural too, that some kind of infix operator works well for args split over several lines due to their length.

I think this reads very easily, HEADERS is 3 env vars added up into one:

HEADERS = ENV["BLAH_BLAH"] +
ENV["BLAH_BLAH_BLAH"] +
ENV["BLAH_BLAH_BLAH_BLAH"]

to this, which creates an array then destroys it, which kind of masks the intention:

HEADERS = [
ENV["BLAH_BLAH"],
ENV["BLAH_BLAH_BLAH"],
ENV["BLAH_BLAH_BLAH_BLAH"]
].inject([1]) {|r,x| x and r.concat(x) or r}

If I was going to use a fold or something similar then I would probably have done something like this, or used a ternary operator in a fold, (knowing the way I think):

HEADERS = [
ENV["BLAH_BLAH"],
ENV["BLAH_BLAH_BLAH"],
ENV["BLAH_BLAH_BLAH_BLAH"]
].reject{|x| x.nil? }.reduce(:+)

but compared to this it seems a bit creaky:

HEADERS = ENV["BLAH_BLAH"] +?
ENV["BLAH_BLAH_BLAH"] +?
ENV["BLAH_BLAH_BLAH_BLAH"]

Is there a way to define infix operators in Ruby, as I quite like this one? :slight_smile:

There is no way to define new operators other than hacking the
interpreter. IMHO it's a bad idea to do this just for a minor
nuisance.

Actually, looking at the code they'd be ENV["BLAH_BLAH"].split(":") as they were PATHs, but I'm not sure the inclusion adds anything to the examples.

I don't understand what's wrong with

HEADERS =
%w{BLAH BLAH_BLAH BLAHHH}.each do |var|
  x = ENV[var] and HEADERS.concat(x.split(/:+/))
end

Nice short concise and yet readable.

Cheers

robert

···

On Fri, Mar 25, 2011 at 4:42 PM, Iain Barnett <iainspeed@gmail.com> wrote:

On 25 Mar 2011, at 14:32, Colin Bartlett wrote:

On Fri, Mar 25, 2011 at 7:52 AM, Robert Klemme >> <shortcutter@googlemail.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Actually, methods are kinda like infix operators anyway. One argument is
followed by the method name, which is followed by any other argument(s):

    irb(main):001:0> 4.div 2
    => 2

The div method fits between the operands, when viewed as an operator. In
fact, that's how other infix operators work:

    irb(main):002:0> 4./ 2
    => 2

I don't know of any way to eliminate the requirement for the dot used
with methods you define, the way built-in operators do, though.

···

On Sat, Mar 26, 2011 at 12:42:25AM +0900, Iain Barnett wrote:

Is there a way to define infix operators in Ruby, as I quite like this one? :slight_smile:

--
Chad Perrin [ original content licensed OWL: http://owl.apotheon.org ]

Is there a way to define infix operators in Ruby, as I quite like this one? :slight_smile:

There is no way to define new operators other than hacking the
interpreter. IMHO it's a bad idea to do this just for a minor
nuisance.

Well, yeah, I won't be hacking the interpreter for this :slight_smile: Just wondering. Is there somewhere I could suggest `+?` as an operator for Ruby 2? It was only an off the cuff remark but I quite like it :slight_smile:

I don't understand what's wrong with

HEADERS =
%w{BLAH BLAH_BLAH BLAHHH}.each do |var|
x = ENV[var] and HEADERS.concat(x.split(/:+/))
end

Nice short concise and yet readable.

I totally agree, there's nothing wrong with that, and out of the suggestions given I think that's the one I like best (which makes me feel better for labouring the point:) It's only that, as I said, Ruby usually has some really nice shortcuts that don't seem like shortcuts, just natural looking. A bit like having to define getters and setters, there's nothing wrong with it, but `attr_accessor :var` is really nice, as is `||=` and it's ilk.

Wouldn't this be quite nice, for instance?

[a,b,c,d].reduce(:+?)

That's all.

Regards,
Iain

···

On 25 Mar 2011, at 16:07, Robert Klemme wrote:

...personally i think it would be nice to be able to define new operators
(like the aforementioned +?) that way when a situation like this comes up,
one can simply:

op_def +? # maybe? i'm assuming it'd have special syntax...
  # stuff
end

and get on with life, making your code cleaner & simpler. IDK how well this
would work or its potential ramifications, but i think it fits into the
'flavor' of ruby to be able to do such things (i mean, you can define/change
damn near *everything else* in the language, why not operators?)
hex

···

On Fri, Mar 25, 2011 at 12:54 PM, Iain Barnett <iainspeed@gmail.com> wrote:

On 25 Mar 2011, at 16:07, Robert Klemme wrote:

>>
>> Is there a way to define infix operators in Ruby, as I quite like this
one? :slight_smile:
>
> There is no way to define new operators other than hacking the
> interpreter. IMHO it's a bad idea to do this just for a minor
> nuisance.

Well, yeah, I won't be hacking the interpreter for this :slight_smile: Just wondering.
Is there somewhere I could suggest `+?` as an operator for Ruby 2? It was
only an off the cuff remark but I quite like it :slight_smile:

>
> I don't understand what's wrong with
>
> HEADERS =
> %w{BLAH BLAH_BLAH BLAHHH}.each do |var|
> x = ENV[var] and HEADERS.concat(x.split(/:+/))
> end
>
> Nice short concise and yet readable.
>

I totally agree, there's nothing wrong with that, and out of the
suggestions given I think that's the one I like best (which makes me feel
better for labouring the point:) It's only that, as I said, Ruby usually has
some really nice shortcuts that don't seem like shortcuts, just natural
looking. A bit like having to define getters and setters, there's nothing
wrong with it, but `attr_accessor :var` is really nice, as is `||=` and it's
ilk.

Wouldn't this be quite nice, for instance?

[a,b,c,d].reduce(:+?)

That's all.

Regards,
Iain

...personally i think it would be nice to be able to define new operators
(like the aforementioned +?) that way when a situation like this comes up,
one can simply:

op_def +? # maybe? i'm assuming it'd have special syntax...
# stuff
end

and get on with life, making your code cleaner & simpler. IDK how well this
would work or its potential ramifications, but i think it fits into the
'flavor' of ruby to be able to do such things (i mean, you can define/change
damn near *everything else* in the language, why not operators?)
hex

I agree. In Haskell, for instance, you can make a prefix function into an infix by surrounding it with backticks, e.g.

    plus 1 2

becomes

    1 `plus` 2

Something similar would be helpful on occasion, IMO.

···

On 25 Mar 2011, at 19:06, serialhex wrote:

On 25 Mar 2011, at 20:06, Ryan Davis wrote:

Yeah. Well... I disagree. We really don't need extra magical syntax. I can almost guarantee you that this proposal would get rejected by ruby-core@, but you're free to ask.

I find that a strange argument, applied across the language and a lot of what is regularly used would be binned. Aliases, attributes and method synonyms would all go immediately.

Regards,
Iain

Because that would completely break parsing. Whenever an operator definition would be seen the whole source would need reparsing - or at least part of it. It would be tricky to determine which part. Think of situations like this:

def foo
   x +? y
end

op_def +?(a,b)
   p a, b
   a + b
end

Now, Ruby would have bailed out with a syntax error already before it could read the new operator definition. If you defer error reporting to a later point in time then execution would become much more complex because parsing would have to occur chunk wise. And the whole thing will likely get slower as well.

If you try something like prescanning all sources for operator definitions before parsing the code then this is not possible because you can easily construct 'require' and 'load' statements which do not have a String constant argument but whose argument is constructed at runtime. So now you have a chicken egg issue: you need to parse the code in order to be able to execute it but you also need to execute the code in order to be able to parse it...

And then of course there are issues of readability. In general I'd say, too much flexibility can rather harm than do good. It's the right balance which is most productive. And IMHO Matz has done a wonderful job at this.

Kind regards

  robert

···

On 25.03.2011 20:06, serialhex wrote:

..personally i think it would be nice to be able to define new operators
(like the aforementioned +?) that way when a situation like this comes up,
one can simply:

op_def +? # maybe? i'm assuming it'd have special syntax...
   # stuff
end

and get on with life, making your code cleaner& simpler. IDK how well this
would work or its potential ramifications, but i think it fits into the
'flavor' of ruby to be able to do such things (i mean, you can define/change
damn near *everything else* in the language, why not operators?)

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Well I'm not applying across the whole language... Otherwise we'd all be coding in assembly. :smiley:

···

On Mar 25, 2011, at 14:22 , Iain Barnett wrote:

Yeah. Well... I disagree. We really don't need extra magical syntax. I can almost guarantee you that this proposal would get rejected by ruby-core@, but you're free to ask.

I find that a strange argument, applied across the language and a lot of what is regularly used would be binned. Aliases, attributes and method synonyms would all go immediately.

But that's something different than defining a new operator. It's just fixed syntax for a method call. That approach doesn't suffer from the problems I laid out in my other reply to this thread.

Kind regards

  robert

···

On 25.03.2011 22:22, Iain Barnett wrote:

On 25 Mar 2011, at 19:06, serialhex wrote:

...personally i think it would be nice to be able to define new operators
(like the aforementioned +?) that way when a situation like this comes up,
one can simply:

op_def +? # maybe? i'm assuming it'd have special syntax...
  # stuff
end

and get on with life, making your code cleaner& simpler. IDK how well this
would work or its potential ramifications, but i think it fits into the
'flavor' of ruby to be able to do such things (i mean, you can define/change
damn near *everything else* in the language, why not operators?)
hex

I agree. In Haskell, for instance, you can make a prefix function
into an infix by surrounding it with backticks, e.g.

     plus 1 2

becomes

     1 `plus` 2

Something similar would be helpful on occasion, IMO.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

An alternative for the original poster's ENV variables potentially
containing colon-separated paths:

%w{FOO BAR BAZ}.map{|x| ENV[x].to_s}.join(':').split(/:+/)

The .to_s should handle nil just fine. Concatenate all the strings,
then do the split.

Aaron out.

I'm not so sure about that. If it were just possible to specify that a
method need not be connected to its object with the "dot", it would give
the appearance of an infix operator for those who really want it, but
would only conform to the standard rules for method calls. The parser
would just have to maintain a last-object context of one to determine
whether what follows is a method to which the last object responds.

Of course, I'm not sure that would be so great a task to dump on the
interpreter, but I don't think it would necessarily be as dire as you
describe, as long as we're willing to recognize that infix arithmetic,
comparison, and assignment operators are actually methods.

Frankly, I'd be happy without infix operator syntax (with its precedence
rules) at all. 2.plus(3) is conceptually simpler than 2 + 3 in the
context of code; so is something like (+ 2 3), add(2,3,), or sum 2 3.

2.plus 3 looks pretty "infix"y to me anyway, but it's still a method call
with obvious meaning and precedence.

···

On Sat, Mar 26, 2011 at 07:21:25PM +0900, Robert Klemme wrote:

>
> IDK how well this would work or its potential ramifications, but i
> think it fits into the 'flavor' of ruby to be able to do such things
> (i mean, you can define/change damn near *everything else* in the
> language, why not operators?)

Because that would completely break parsing. Whenever an operator
definition would be seen the whole source would need reparsing - or at
least part of it. It would be tricky to determine which part.

--
Chad Perrin [ original content licensed OWL: http://owl.apotheon.org ]

I was heard to muse:

An alternative for the original poster's ENV variables potentially
containing colon-separated paths:

%w{FOO BAR BAZ}.map{|x| ENV.to_s}.join(':').split(/:+/)

The .to_s should handle nil just fine. Concatenate all the strings,
then do the split.

Append a .uniq to that as desired. Or do:
%w{FOO BAR BAZ}.map{|x| ENV.to_s.split(/:+/) || }.flatten.uniq

Aaron out.