Hi --
rather than simply
asking an object to do something at the moment you want it to do that
thing, you're introducing a wrapper/notation mechanism
Not always true. Below I've dropped many of the ':' as I think they are not
syntactically essential.
[x,y] = obj
is the same as
x = obj[0]
y = obj[1]
So I ask obj to 'do' its [0], [1] right where I want it. Variables are bound
to results.
Hmmm...
irb(main):004:0> obj = [1,2]
=> [1, 2]
irb(main):005:0> [x,y] = obj
SyntaxError: compile error
Or did you mean: x,y = obj ? I don't think I'd characterize it as obj
"doing its [0], [1]". You're not sending messages to obj -- not even
the message #. What happens in this scenario depends on assignment
semantics, not message semantics. Also I think you're playing on the
similarity of the literal array constructor and the method #,
which I think has to be discounted as something of a coincidence ![:slight_smile: :slight_smile:](https://emoji.discourse-cdn.com/twitter/slight_smile.png?v=12)
(And, as above, that syntax doesn't parse.)
(m1(obj1) x, m2(obj2) y) = obj
is the same as
x = obj.m1(obj1)
y = obj.m2(obj2)
Again, I ask obj to do it's m1(), m2() right where I want it. Variables are
bound to results.
You can devise some very obscure notation in which things happen and
the results are saved in variables
I don't think that, in itself,
makes a case one way or the other. I'm feeling very reactionary here,
because I vastly prefer your 'unrolled' ("same as...") version. I
don't really get that other syntax; it seems confusing to put the
messages being sent to obj on the other side of the assignment from
obj itself. What would you gain by that?
x = obj
Object x = obj
are identical.
Now
T x = obj
would be
x = obj
assert x.is_of_type(T)
# Object#is_of_type would handle named types, type patterns, classes,
etc.
It could be an interesting experiment (and it's been attempted), but I
don't know that such a thick description of an object at a given
moment in its life-cycle would have much practical value. There are
mainly two things at stake: whether to send a message to an object,
and what will happen when you do. To make a reasonable judgement
about the former, the most you need to know is whether the object
responds at all to the message. As for the second (what the object
will do), you literally cannot know without sending the message, so no
amount of thick description will help you there.
I wonder whether any full run-time type-capturing facility in Ruby
might therefore be doomed to being overengineered, even if quite
interesting.
...[can] prevent you from getting to that point at all
under certain conditions.
Yes, this pattern matching can fail, and depending on context might
sometimes raise errors e.g. In places like a case-when or if- statement a
match can fail without raising any error; its just a boolean check, with the
added bonus of variable bindings from a successful match. In a regular
assignment it can fail to match and will raise the same errors as the
equivalent regular ruby code.
- [x,y]=obj : can raise same errors as x=obj[0], y=obj[1]
- (m1(), m2()) x = obj can raise errors from 'assert x.respond_to...'
That doesn't make it good or bad in itself -- it
would just be clearer, I think, not to label it duck typing.
I see. Some usages of it are intentionally closer to explicit type
declarations. Maybe 'duck type declarations'?
I believe that duck typing and type declaration are two different
things -- i.e., that the concept of duck typing is at heart an
alternative to the concept of type declaration. In any case, if you
declare/describe/document what a Ruby object can do at a given moment,
you are declaring/etc. its *type*, not its "duck type". In other
words, that's what type *is* in Ruby. If you call this an object's
"duck type", it suggests that there's some other "type" that an object
can have -- which, frequently if not inexorably, leads back to
the type == class thing.
Maybe there's some way to develop the pattern-matching idea but not
necessarily put it all in the method signature.
Yes. For example we could put this info right after the def f(x,y) so the
def line is uncluttered. Something like this would be ok.
def f ( x, y )
(m1(), m2()) x
# or T x, if T was named type defined as m1(), m2()
In this case Ruby should associate the type-declared x with the parameter x,
rather than a new local variable. Would you agree?
In context, yes, but I'm not sold on this syntax either. m1() looks
like a method call. If you're querying whether a method *can* be
called, but not calling it, I'd rather use something that doesn't look
like a method call. #respond_to?(sym) comes to mind.... ![:slight_smile: :slight_smile:](https://emoji.discourse-cdn.com/twitter/slight_smile.png?v=12)
Could incremental
things, like allowing #respond_to? to take an array or multiple
arguments, work in that direction?
I see where you are going. Do you mean:
def f(x)
x.respond_to? :m1, :m2, :m3
I did want to somehow distinguish patterns used as type declarations from a
regular (and overridable!) method call like respond_to. There may be other
alternatives to "punctuation", but how would using 'normal' respond_to would
for this purpose?
I just wonder whether letting respond_to? take multiple arguments
might actually solve, in practice, 99% of the perceived problems in
this realm. Or even wrapped, like so:
module Kernel
def can?(*methods)
methods.all? {|m| respond_to?(m) }
end
end
class C
def blah(x)
raise ArgumentError unless x.can?(:a,:b,:c)
end
end
which looks strangely familiar.... I think that I or someone else
wrote something very like that at some other point.
David
···
On Tue, 11 Jan 2005, itsme213 wrote:
"David A. Black" <dblack@wobblini.net> wrote
--
David A. Black
dblack@wobblini.net