On 9/9/10 6:33 AM, "Martin J. Drst" wrote:
> On 2010/09/09 3:50, Kurt Stephens wrote:
>
>> ---------------------------------------------------
>>
>> I'd like to implement:
>>
>> x // y # and x //= y
>>
>> =>
>>
>> (tmp = x) != nil ? tmp : y

Excuse my mistake, perhaps this should be:

   (tmp = x).nil? ? nil : y

Thus:

   x //= y

=>

   (tmp = x).nil? ? (x = y) : tmp

E.g.:

   x[:foo] //= 123

=>

   (tmp2 = (tmp1 = x)[:foo]).nil? ? (tmp1[:foo] = y) : tmp2

Works like &&=, except will not clobber false lhs.

This greatly simplifies setting non-nil defaults.

I believe this is a also a perl6 construct.  Since "//" and "//=" are 
binary operators they should not conflict with "//" as the empty Regexp.
But they would certainly complicate the lexer/parser.

>
> One case that I remember having met frequently, and that seems to be
> related to this, is:
> In a method chain, apply methods successively, except if the receiver is
> nil, in which case, just keep it as nil.
>
> As an example, I'd like to write something like:
>
> ((tmp1=a).nil? ? nil : tmp1.method1(args))
>
> as something like:
>
> a.unless_nil.method1(args)

See &&. below.

>
>> And
>>
>> x&&.y&&.z # and x//.y//.z
>>
>> =>
>>
>> (tmp = x) && (tmp = tmp.y) && tmp.z
>
> Shouldn't that be
> (tmp = x) && tmp.y && tmp.z ? That would make more sense to me. Also,is
> there a way to express this as a binary operator?
>

   rcvr &&. selector

=>

   (tmp = rcvr) && tmp.selector

Consider:

   x&&.y&&.z

similar to

   x.y.z

but with false checks on each LHS expr.

> And what's the semantics of x//.y//.z ?
>

   rcvr //. selector

=>

   (tmp = rcvr).nil? ? nil : tmp.selector


Thus:

   x//.y//.z

is similar to:

   x.y.z

but with nil checks on each LHS expr.

This simplifies code like:

   if x && x.y && x.y.z
     ...
   end

Which, if #x, X#y or Y#z are expensive methods, is sometimes rewritten:

   if (tmp = x) && (tmp = tmp.y) && (tmp = tmp.z)
     ...
   end

This leads to a .= operator :)

   if (tmp = x) && (tmp .= y) && (tmp .= z)
     ...
   end

   lhs .= mcall(*margs)

=>

   lhs = lhs.mcall(*margs)

i.e:

   lhs &&= val

=>

   lhs = lhs && val

> Regards, Martin.
KAS