Array#[]=

I'm writing a class representing a coordinate system, and I want to be able to give a point in the system a value (eg. a label). The problem is that the system can have a variable number of dimensions. If it just had three, I could write:

   def []= (x, y, z, value); end

But this being an N-dimensional coordinate system, I have to come up with something else. The most logical solution to me is this:

   def[]= (*coordinates, value); end

But this gives a syntax error. Am I way off base, or would it be useful if variable length argument lists could be written this way?

Daniel

If the slurpy arrays could be used anywhere in the list, if becomes impossible to parse the arguments correctly.

In this case, you'll need to separate the value yourself:

def =( *args )
     value = args.pop
     cooridinates = args
     # ...
end

Hope that helps.

James Edward Gray II

···

On Sep 11, 2005, at 1:01 PM, Daniel Schierbeck wrote:

I'm writing a class representing a coordinate system, and I want to be able to give a point in the system a value (eg. a label). The problem is that the system can have a variable number of dimensions. If it just had three, I could write:

  def = (x, y, z, value); end

But this being an N-dimensional coordinate system, I have to come up with something else. The most logical solution to me is this:

  def= (*coordinates, value); end

But this gives a syntax error. Am I way off base, or would it be useful if variable length argument lists could be written this way?

def =(*a)
     value = a.pop
     coordinates = a
     raise ArgumentError if value.nil? or coordinate.empty?
     ...
   end

hth.

-a

···

On Mon, 12 Sep 2005, Daniel Schierbeck wrote:

I'm writing a class representing a coordinate system, and I want to be able to give a point in the system a value (eg. a label). The problem is that the system can have a variable number of dimensions. If it just had three, I could write:

def = (x, y, z, value); end

But this being an N-dimensional coordinate system, I have to come up with something else. The most logical solution to me is this:

def= (*coordinates, value); end

But this gives a syntax error. Am I way off base, or would it be useful if variable length argument lists could be written this way?

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

===============================================================================

Daniel Schierbeck wrote:

dimensions. If it just had three, I could write:

  def = (x, y, z, value); end

But this being an N-dimensional coordinate system, I have to come up with something else. The most logical solution to me is this:

  def= (*coordinates, value); end

But this gives a syntax error. Am I way off base, or would it be useful if variable length argument lists could be written this way?

Yes, that would be useful. It has been discussed many-a-time, before, too. :slight_smile: For now, you'll have to implement your own solution in-method:
def = *args
  cords, value = args[0..-2],args[-1]
  #...
end

Personally, I'd also like to see this:

def = x, y, value
  #...
ordef x, y, z, value
  #...
ordef *args #gets here only if neither of the first two match
  #...
end

But none of this exists. So live with it. :slight_smile:

(I'd say, "Go write an RCR," but I can't imagine that 3 don't exist already.)

Devin

Coincidentally, I was just writing an RCR for this one. It is
#315. I'm also writing the corollary to this one which is to
be able to call a method with more arguments after the splat
(also applies to multi-assigns).

···

--- Daniel Schierbeck <daniel.schierbeck@gmail.com> wrote:

I'm writing a class representing a coordinate system, and I
want to be
able to give a point in the system a value (eg. a label). The
problem is
that the system can have a variable number of dimensions. If
it just had
three, I could write:

   def = (x, y, z, value); end

But this being an N-dimensional coordinate system, I have to
come up
with something else. The most logical solution to me is this:

   def= (*coordinates, value); end

But this gives a syntax error. Am I way off base, or would it
be useful
if variable length argument lists could be written this way?

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around

James Edward Gray II wrote:

···

On Sep 11, 2005, at 1:01 PM, Daniel Schierbeck wrote:

I'm writing a class representing a coordinate system, and I want to be able to give a point in the system a value (eg. a label). The problem is that the system can have a variable number of dimensions. If it just had three, I could write:

  def = (x, y, z, value); end

But this being an N-dimensional coordinate system, I have to come up with something else. The most logical solution to me is this:

  def= (*coordinates, value); end

But this gives a syntax error. Am I way off base, or would it be useful if variable length argument lists could be written this way?

If the slurpy arrays could be used anywhere in the list, if becomes impossible to parse the arguments correctly.

In this case, you'll need to separate the value yourself:

def =( *args )
    value = args.pop
    cooridinates = args
    # ...
end

Hope that helps.

James Edward Gray II

Thanks! That looks a lot better.

Daniel

Devin Mullins wrote:

Daniel Schierbeck wrote:

> dimensions. If it just had three, I could write:
>
> def = (x, y, z, value); end
>
> But this being an N-dimensional coordinate system, I have to come up
> with something else. The most logical solution to me is this:
>
> def= (*coordinates, value); end
>
> But this gives a syntax error. Am I way off base, or would it be
> useful if variable length argument lists could be written this way?

Yes, that would be useful. It has been discussed many-a-time, before,
too. :slight_smile: For now, you'll have to implement your own solution in-method:
def = *args
  cords, value = args[0..-2],args[-1]
  #...
end

Personally, I'd also like to see this:

def = x, y, value
  #...
ordef x, y, z, value
  #...
ordef *args #gets here only if neither of the first two match
  #...
end

But none of this exists. So live with it. :slight_smile:

(I'd say, "Go write an RCR," but I can't imagine that 3 don't exist
already.)

I think that you have the right sentiment, but the implemenation isn't
so good. It would make methods more compicated things to deal with. To
achieve signiture bases defintoins I think its best to stick with
multiple definitions:

  def = x, y, value
    #...
  end

  def = x, y, z, value
    #...
  end

  def = *args #gets here only if neither of the first two match
    #...
  end

I have often though they would be nice too. But how would you
distingush one from the other, by arity? Eg. #method(:=, 3) ?

T.

Trans wrote:

I think that you have the right sentiment, but the implemenation isn't
so good. It would make methods more compicated things to deal with. To
achieve signiture bases defintoins I think its best to stick with
multiple definitions:

There are a couple of problems with the typical definition of multiple defs:
1. Matz has said that he won't implement them. :slight_smile:
2. What method are you refering to when you call method, remove_method, etc.? In Ruby, the method signature is its name -- changing that would be a bigger deal.
3. It doesn't play well with inheritance. Suddenly you've got to think really hard when overriding a method (making sure to remove all implementations with different arity, or whatever).
4. It doesn't play well with optional args and splats. My way establishes an obvious order of resolution -- if the first one doesn't match, go onto the next one. The typical way doesn't, and is one of the confusing things about method overloading in C++ (by type in that case, but same diff).

My way might squish ordef definitions together a little more (though you're free to use blank lines), but it maintains the idea of a method as an atomic unit -- the ordef thing is just an assistant to make dealing with different arities nice. It would make method definitions as complicated as you make them. If you really have one method doing three different things based on arity, then your central ordef thing should be nothing but a dispatcher to other methods.

The one problem I see with it -- not reproducible by blocks and define_method. But, in that case, just do it the old fashioned way, as has already been covered on this thread.

The other is that, if it were adopted, the next thing asked for would be ordef's based on ===:

def foo String => bar
ordef foo Regexp => bar
end

def foo "add" => action, *args
ordef foo "delete" => action, *args
end

And that would condone some pretty obvious smells. :slight_smile:

Devin

Devin Mullins wrote:

Trans wrote:

>I think that you have the right sentiment, but the implemenation isn't
>so good. It would make methods more compicated things to deal with. To
>achieve signiture bases defintoins I think its best to stick with
>multiple definitions:
>
>
There are a couple of problems with the typical definition of multiple defs:
1. Matz has said that he won't implement them. :slight_smile:
2. What method are you refering to when you call method, remove_method,
etc.? In Ruby, the method signature is its name -- changing that would
be a bigger deal.
3. It doesn't play well with inheritance. Suddenly you've got to think
really hard when overriding a method (making sure to remove all
implementations with different arity, or whatever).
4. It doesn't play well with optional args and splats. My way
establishes an obvious order of resolution -- if the first one doesn't
match, go onto the next one. The typical way doesn't, and is one of the
confusing things about method overloading in C++ (by type in that case,
but same diff).

My way might squish ordef definitions together a little more (though
you're free to use blank lines), but it maintains the idea of a method
as an atomic unit -- the ordef thing is just an assistant to make
dealing with different arities nice. It would make method definitions as
complicated as you make them. If you really have one method doing three
different things based on arity, then your central ordef thing should be
nothing but a dispatcher to other methods.

The one problem I see with it -- not reproducible by blocks and
define_method. But, in that case, just do it the old fashioned way, as
has already been covered on this thread.

You make some good points. But it occurs to me that having seperated
defs could in effect work in the same way as what you propose, with the
excpetion of controlling the order --but that I think should be airty
dictated anyway. How does the following, for instance, make any sense:

  def x(*a)
    ...
  ordef x(a)
    ...
  end

If it works like a case statement, the the last will never be reached.
Also if this is just a helper, you probaby could do it now with a case
statement, let me see...

  def x(*args)
    case args.size
    when 0
      ...
    when 1
      a = *args
      ...
    when 2
      a,b = *args
      ...
    else
      ...
    end
  end

Pretty simpe, if not quite as concise. Also I reacall a "real" solution
to this somewhere --writen by an old school Japanese Ruby Hacker. But I
can't seem to track it down. Anyone recall?

The other is that, if it were adopted, the next thing asked for would be
ordef's based on ===:

def foo String => bar
ordef foo Regexp => bar
end

def foo "add" => action, *args
ordef foo "delete" => action, *args
end

And that would condone some pretty obvious smells. :slight_smile:

You betchya :slight_smile:

T.

Trans wrote:

If it works like a case statement, the the last will never be reached.

Yep. Shame on whomever wrote that code! :stuck_out_tongue:

Also if this is just a helper, you probaby could do it now with a case
statement, let me see...

<snip/>

Pretty simpe, if not quite as concise.

Yeah, I guess what I'm seeking is a concise way to write that. Maybe it's not deserving of its own construct, though. Can you think of a more general solution that gets half-way there? Maybe a pattern-matching thing akin to the way OCaml does case statements...

def x(*args)
  case args
    when then ...
    when [a] then ...
    when [a,b] then ...
    else ...
  end
end

That is totally un-Ruby, of course, so, I dunno.

Also I reacall a "real" solution
to this somewhere --writen by an old school Japanese Ruby Hacker. But I
can't seem to track it down. Anyone recall?

'd be interested to hear.

Thanks,
Devin

hmmm....

  # holds some nift binding methods like []=
  # for setting local vars, essentially

···

#
  # eval %{ #{var}=#{val} }, binding
  #
  require 'nano/binding'

  class Array
    def to_p(bind)
      P.new(bind,*self)
    end
  end

  class P < Array
    attr_reader :bind
    def initialize(*args)
      super()
      @bind = args.shift if Binding === args.first
      self.replace(args)
    end
    def ===(args)
      if size == args.size
        each_with_index{ |k, i|
          args.bind[k] = args[i]
        }
        return true
      else
        return false
      end
    end
  end

  def prms(bind,*args)
    Params.new(bind,*args)
  end

  def x(*args)
    a,b = nil,nil
    case args.to_p(binding)
    when P[] then p []
    when P[:a] then p [a]
    when P[:a,:b] then p [a,b]
    else
      puts "don't know"
    end
  end

  x
  x(1)
  x(1,2)
  x(1,2,3)

Oh, you can ignore/delete this part:

  def prms(bind,*args)
    Params.new(bind,*args)
  end

T.