Forum: Ruby Typed Parameters

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2006-04-01 23:10
(Received via mailing list)
Dear group

there was a recent thread about "Boolean" and it braught me to my
favorit
thing I would love to have in Ruby2.

*typed parameters*

My code is completely filled with things like this:

 def never_saw_a_better_method( clever, smart, stupid )
            assert_type clever, String
           assert_type  smart, Hash
          assert_type  stuoid, Boolean
....
def cool( clever : String, smart : Hash, stupid : Boolean )

and of course
def x(y)  would be equivalent to def(x : Object )

There is no other than practical reason to that, I found that this kind
of
type assertion finds the most devious bugs in my code.

Thaughts?

Robert
--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
31ab75f7ddda241830659630746cdd3a?d=identicon&s=25 Austin Ziegler (Guest)
on 2006-04-02 01:18
(Received via mailing list)
On 4/1/06, Robert Dober <robert.dober@gmail.com> wrote:
> Dear group
>
> there was a recent thread about "Boolean" and it braught me to my
> favorit thing I would love to have in Ruby2.
>
> *typed parameters*

This might happen, but it's unlikely to work the way you have
suggested. I personally hope it doesn't happen, as it will make
Ruby a little less "smart."

> def x(y)  would be equivalent to def(x : Object )
>
> There is no other than practical reason to that, I found that this
> kind of type assertion finds the most devious bugs in my code.

It's not actually that practical, and such things end up making your
code very much like C++ and Java.

Ruby is smarter than that. Ruby can do more than that.

Think in terms of what your object's required capabilities are instead
of pretending that a class indicator is sufficient for that.

-austin
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2006-04-02 02:41
(Received via mailing list)
<blockquote>
It's not actually that practical, and such things end up making your
code very much like C++ and Java.

Ruby is smarter than that. Ruby can do more than that.

Think in terms of what your object's required capabilities are instead
of pretending that a class indicator is sufficient for that.
</blockquote>

While I understand you pointr Austin --obviously where talking Duck
Typing here. But I think it is interesting to condier that this is some
respect antithetical to OOP in general --I mean the reciever _is_ a
specific type. And that reacieve detemine the functionality of the
method call. It is sort of as if you were progamming in a more
traditional functional language and _had_ to specifiy the type of the
first argument, but never the remaining.

  foofunc(  FooClass foo, clever, smart, stupid )

instead of

  foo.foofunc( clever, smart, stupid )

So why shouldn't any of the other participating objects have a
selective effect too?

T.
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-04-02 03:00
(Received via mailing list)
Hi --

On Sun, 2 Apr 2006, Trans wrote:

> While I understand you pointr Austin --obviously where talking Duck
>
>  foo.foofunc( clever, smart, stupid )

It's actually more like this:

   foofunc(object_that_responds_to_foofunc, etc.)

The fact that an object handles a message does not imply its class.
(I'm transliterating 'type' to 'class' as that seems to be what the
thread is actually about [as it usually is :-].)

> So why shouldn't any of the other participating objects have a
> selective effect too?

Because there's no applicable general notion of "a selective effect."
Each of these things is a different part of a system.


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
5dfb03e2e567dcbe857efa96f998d499?d=identicon&s=25 gabriele renzi (Guest)
on 2006-04-02 03:09
(Received via mailing list)
Trans ha scritto:
> So why shouldn't any of the other participating objects have a
> selective effect too?

<noise type="useless">
I agree, let's stop this antidemocratic self-proclaimed dictatorship of,
well, self.
(and recall that our uncle Common Lisp had dynamic typing and multiple
dispatch for decades withouth becoming Java :)
</noise>
70c8da82d09d3866222976ab8978133c?d=identicon&s=25 Daniel Nugent (Guest)
on 2006-04-02 03:12
(Received via mailing list)
Well, I think you should allowed to put a selective effect on the
remaining arguments, but it should at least allow you to be a little
smarter than simply checking one single Type.  I'd like to see you
able to check against multiple types as well as methods and
combinations thereof, like

def foo(arg1 : (Array and :custom_array_method) or Hash or
:special_method)

Then at least it's simply a syntactic convenience for writing
respond_to? and kind_of? calls.  And, logically, you should be able to
assign these parameter checks to a variabe so you can reduce the
duplication of them, although I don't have a clue as to what a good
syntax for that would be... Maybe something like:

type_check = TypeCheck.new do |var|
  case var
  when Array
    return true if var.respond_to? :custom_array_method
  when Hash
    return Hash
  else
    return true if var.respond_to? :special_method
  end
  return false
end

And, of course, you can do any checking you want in the block. You
could then do this:

def foo(arg1 : type_check)
def bar(arg1, arg2 : type_check)

On 4/1/06, Trans <transfire@gmail.com> wrote:
> While I understand you pointr Austin --obviously where talking Duck
>
>   foo.foofunc( clever, smart, stupid )
>
> So why shouldn't any of the other participating objects have a
> selective effect too?
>
> T.
>
>
>


--
-Dan Nugent

Don't Feel Like Typing?  Send me a voicemail:
http://odeo.com/sendmeamessage/DanNugent
70c8da82d09d3866222976ab8978133c?d=identicon&s=25 Daniel Nugent (Guest)
on 2006-04-02 03:15
(Received via mailing list)
Actually... now that I'm looking about it, that's kinda dumb, we might
as well just add pre, post, and around calls so we can more cleanly
seperate the Type and condition checks from the actual method.

On 4/1/06, Daniel Nugent <nugend@gmail.com> wrote:
> assign these parameter checks to a variabe so you can reduce the
>     return true if var.respond_to? :special_method
> On 4/1/06, Trans <transfire@gmail.com> wrote:
> > While I understand you pointr Austin --obviously where talking Duck
> >
>
> --
> -Dan Nugent
>
> Don't Feel Like Typing?  Send me a voicemail:
> http://odeo.com/sendmeamessage/DanNugent
>


--
-Dan Nugent

Don't Feel Like Typing?  Send me a voicemail:
http://odeo.com/sendmeamessage/DanNugent
70c8da82d09d3866222976ab8978133c?d=identicon&s=25 Daniel Nugent (Guest)
on 2006-04-02 03:24
(Received via mailing list)
Maybe the code for that could look something like this:

def foo(arg1, arg2)
  BLAHBLAHBLAH STUFF GOES HERE
end.pre do |*args|
  SOME MORE STUFF
end.post do |*result|
  A LITTLE MORE
end.around do|*args, &method|
  SOME
  method.call(transformed_args)
  STUFF
end

And then you could dynamically add and remove the pre and post
conditions or whatever.

On 4/1/06, Daniel Nugent <nugend@gmail.com> wrote:
> >
> >   when Array
> > could then do this:
> > >
> > > first argument, but never the remaining.
> > > T.
> >
>
>
> --
> -Dan Nugent
>
> Don't Feel Like Typing?  Send me a voicemail:
> http://odeo.com/sendmeamessage/DanNugent
>


--
-Dan Nugent

Don't Feel Like Typing?  Send me a voicemail:
http://odeo.com/sendmeamessage/DanNugent
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2006-04-02 04:00
(Received via mailing list)
dblack@wobblini.net wrote:
> > Think in terms of what your object's required capabilities are instead
> >
> The fact that an object handles a message does not imply its class.
> (I'm transliterating 'type' to 'class' as that seems to be what the
> thread is actually about [as it usually is :-].)

But the class of that object dictates the functionality of that
message. That's my point --it's class based.  A double dispath makes
this very clear:

  class String
    def from( obj )
      # the parameter is type String no matter what
      obj.to( self )
    end
  end

We can even do some fancy dispatching to achieve type parameters:

  class String
    def cool( *args )
      args.shift.cool_string( self, *args )
    end
  end

  class Hash
    def cool_string( str, *args )
      args.shift.cool_string_hash( str, self )
    end
  end

  class Boolean
    def cool_string_hash( str, hsh  )
      p str.class, hsh.class, self.class
    end
  end

  def cool( clever, smart, stupid )
    clever.cool( smart, stupid )
  end

  cool( "a string", { :a=>'hash' }, Boolean.new )

produces

  String
  Hash
  Boolean

but

  cool( 1, 2, 3 )  # => NoMethodError

T.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2006-04-02 04:09
(Received via mailing list)
Daniel Nugent wrote:
> Actually... now that I'm looking about it, that's kinda dumb, we might
> as well just add pre, post, and around calls so we can more cleanly
> seperate the Type and condition checks from the actual method.

No, it's not so dumb actually. A system like the one you propose could
be used for multi-dispatch --mere method wraps could not, they'd just
be a more formal way of doing what we already must do using case
statments.

I actually wrote a system much like teh one you propose called
LightType, it was based on the Euphoria language's type system. Hmm...
at the time I didn't hink of using multi-dispatch with it. Since I
recently wrote a working overload method maybe I'll revist the
possibility.

T.
70c8da82d09d3866222976ab8978133c?d=identicon&s=25 Daniel Nugent (Guest)
on 2006-04-02 04:25
(Received via mailing list)
Hrm... I see, however, effective multi-dispatch would still be
possible with only around calls.  Simply make the public method a
dummy:

def public_dummy(*args);end.around do |*args|
  SOME_ARGUMENT_CONDITION CODE
  when CONDITION 1
    real_method_1
  when CONDITION 2
    real_method_2
  else
    real_method_general
  end
end

And, I would say that this is perfectly acceptable because the number
of times you actually NEED multi-methods in Ruby is going to be pretty
small.

On 4/1/06, Trans <transfire@gmail.com> wrote:
>
> I actually wrote a system much like teh one you propose called
> LightType, it was based on the Euphoria language's type system. Hmm...
> at the time I didn't hink of using multi-dispatch with it. Since I
> recently wrote a working overload method maybe I'll revist the
> possibility.
>
> T.
>
>
>


--
-Dan Nugent

Don't Feel Like Typing?  Send me a voicemail:
http://odeo.com/sendmeamessage/DanNugent
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2006-04-02 09:04
(Received via mailing list)
On 4/2/06, Austin Ziegler <halostatue@gmail.com> wrote:
> suggested. I personally hope it doesn't happen, as it will make
> >
>
> Think in terms of what your object's required capabilities are instead
> of pretending that a class indicator is sufficient for that.
>
> -austin
> --
> Austin Ziegler * halostatue@gmail.com
>                * Alternate: austin@halostatue.ca
>

Austin as I have the highes admiration to your contribution to the
community, these are claims without any evidence.
Would you care to provide some?
I'd really appreciate.

Robert

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2006-04-02 09:04
(Received via mailing list)
On 4/2/06, Daniel Nugent <nugend@gmail.com> wrote:
> Then at least it's simply a syntactic convenience for writing
>     return Hash
> def bar(arg1, arg2 : type_check)
> > </blockquote>
> >
> >
I quite agree, showes my how helpless I braught this up. :-(
Should have named the thread "Easier ways to enforce contracts".
Is that not strange that we think types immediately and than are afraid
of
ancient Computer Science History.

Now there is another point.

My programs often pass objects of an unexpected "contract, behavior,
type,
mixin interface" you name it.
I would like a modern language to help me, the *stupid* programmer to be
more *effective*
Ruby claims that.

So let me suggest the following syntax

def foo (bar, foobar)  is a shortcut to
def foo( bar, foobar : Object) which is a shortcut to
def foo( bar, foobar : { |para| Object === para } )  so we can put any
constraint in there.

I still think that is a good thing for readability and maintenance and
*nobody* would be forced to use it.
Furthermore we are not forced to use the block inside the formal
parameter
list, it would just give us the opportunity.

I really fail to see why this is inhibiting the language.
Such programs fail explicitly and early, which is better (I claim) than
maybe failing later or just not behaving as expected.

Robert



--
> -Dan Nugent
>
> Don't Feel Like Typing?  Send me a voicemail:
> http://odeo.com/sendmeamessage/DanNugent
>
>


--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
5dfb03e2e567dcbe857efa96f998d499?d=identicon&s=25 gabriele renzi (Guest)
on 2006-04-02 13:46
(Received via mailing list)
Daniel Nugent ha scritto:

> And, I would say that this is perfectly acceptable because the number
> of times you actually NEED multi-methods in Ruby is going to be pretty
> small.

care to elaborate?

I don't think you're saying that we can't do things withouth
multimethods, but just in case, a cpu with only
SUBTRACT_AND_BRANCH_IF_NEGATIVE is perfectly fine to do everything, but
this does not make it pleasant.
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-04-02 13:52
(Received via mailing list)
Hi --

On Sun, 2 Apr 2006, Trans wrote:

>>> Ruby is smarter than that. Ruby can do more than that.
>>> traditional functional language and _had_ to specifiy the type of the
>>    foofunc(object_that_responds_to_foofunc, etc.)
>>
>> The fact that an object handles a message does not imply its class.
>> (I'm transliterating 'type' to 'class' as that seems to be what the
>> thread is actually about [as it usually is :-].)
>
> But the class of that object dictates the functionality of that
> message. That's my point --it's class based.  A double dispath makes
> this very clear:

No: the definition of the method dictates the functionality of the
method.  That can vary from one instance to another, even within a
class.  It often doesn't; but because it *can*, one can view the case
where two instances of a class behave the same way as a special case
of the case where they don't.


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-04-02 13:55
(Received via mailing list)
Hi --

On Sun, 2 Apr 2006, gabriele renzi wrote:

> perfectly fine to do everything, but this does not make it pleasant.
Well, *something* is making Ruby pleasant, so the absence of this
other stuff can't be too big a problem :-)


David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
31ab75f7ddda241830659630746cdd3a?d=identicon&s=25 Austin Ziegler (Guest)
on 2006-04-02 15:30
(Received via mailing list)
On 4/2/06, Robert Dober <robert.dober@gmail.com> wrote:
>> Then at least it's simply a syntactic convenience for writing
>>     return Hash
>> def bar(arg1, arg2 : type_check)
> I quite agree, showes my how helpless I braught this up. :-( Should
> have named the thread "Easier ways to enforce contracts". Is that not
> strange that we think types immediately and than are afraid of ancient
> Computer Science History.

In Ruby, at least, inheritance is not a guarantee of a contract (even on
objects derived from core classes). It's far better to think in terms of
what an object must *do* in your method, rather than to try to consider
what they *are* in your method. An example might help.

Transaction::Simple has a debug mechanism. It expects an object that can
respond to #<< for output (and I believe *checks* for it). By default,
that means that I support String, Array, IO (and most, if not all,
descendants), and StringIO. I explicitly wanted it this way, whereas if
I had placed a class check (and make no mistake: most people are
familiar with statically typed languages and the addition of this will
make people think of Ruby in terms of static typing), I would have
prevented the use of all but the class(es) that I explicitly specified.

Unless you have a *damn* good reason to restrict a method to a
particular class, you shouldn't be doing any sort of checking at all
that way. Checking on method presence (e.g., #respond_to?) is more
useful (but only partially so; you should check the #arity of a method),
but even that fails if the person forgets to implement #respond_to? when
they've implemented #method_missing. It's also an extra run-time check
that, well, Ruby already does for you.

Make no mistake: I'm not afraid of static typing. I just think that it's
useless in the context of real software development. I've been
developing software for ... a long time. Professionally a little less
than that. ;) I really *cannot* think of a time when I found that static
typing did anything except get in my way.

> My programs often pass objects of an unexpected "contract, behavior,
> type, mixin interface" you name it. I would like a modern language to
> help me, the *stupid* programmer to be more *effective* Ruby claims
> that.

It's called "unit tests." If your programs are often passing objects
that don't behave the way you want those objects to behave, then it's a
bug that you should be ensuring doesn't come out of the caller; in Ruby
it's often far more efficient to ensure that the caller doesn't screw up
instead of the callee doing checks ... that Ruby already does. This is
one reason I'm so consistently opposed to the Eater Nil that is
periodically proposed: it changes the behaviour to silently fail instead
of noisily fail if I get something I'm not supposed to (usually a nil;
in the stuff that I've developed, you won't typically get a Real Object
that doesn't work).

> So let me suggest the following syntax
>
> def foo (bar, foobar)  is a shortcut to
> def foo( bar, foobar : Object) which is a shortcut to
> def foo( bar, foobar : { |para| Object === para } )  so we can put any
> constraint in there.

> I still think that is a good thing for readability and maintenance and
> *nobody* would be forced to use it. Furthermore we are not forced to
> use the block inside the formal parameter list, it would just give us
> the opportunity.

It's exceedingly ugly. It's also no better, in implementation terms,
than placing the contract enforcement as lines of code at the top of the
method. Except that the latter is clearer, explicit, and infinitely more
maintainable than writing a miniprogram in the parameter list. (And can
easily be extracted to a unit test where that sort of thing probably
belongs in most Ruby code.)

Don't get me wrong: there are times when specifying a type is necessary.
Those types when you're dealing with pure Ruby are vanishingly small.
I'm looking at implementing some metacode for PDF::Core that includes
class specification (because the PDF specification has a defined number
of object classes). If I'm interacting with SOAP, it is useful to
specify the types/classes that I'm interacting with.

(I would also suggest that if you're going to allow a block for this
sort of thing, you need to actually allow for inter-parameter validation
as well, e.g., if bar is String then foobar must be Fixnum; if bar is
Fixnum, then foobar must be String. Of course, that gets into more
complex validation, which really does underscore my point that this
behaviour belongs in the method itself. Maybe we can have precondition
and postcondition sections of methods, but putting all this in the
parameter list is ugly and nonsensical.)

> I really fail to see why this is inhibiting the language. Such
> programs fail explicitly and early, which is better (I claim) than
> maybe failing later or just not behaving as expected.

Ah. That's where you're wrong: such programs would not fail any earlier
than they do now. The singular "advantage" to statically typed languages
is that they fail during the compile stage if there's a mismatch. Your
method still won't fail until it is called.

-austin
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2006-04-02 15:55
(Received via mailing list)
On 4/2/06, Austin Ziegler <halostatue@gmail.com> wrote:
> >> :special_method)
> >>     return true if var.respond_to? :custom_array_method
> >>
> >> def foo(arg1 : type_check)
> >> def bar(arg1, arg2 : type_check)
>
> > I quite agree, showes my how helpless I braught this up. :-( Should
> > have named the thread "Easier ways to enforce contracts". Is that not
> > strange that we think types immediately and than are afraid of ancient
> > Computer Science History.
>
> In Ruby, at least, inheritance is not a guarantee of a contract (even on
> objects derived from core classes).


That is a very delicate point too, I strongly feel that  a developper
should
*know* what kind of protocol an object is implementing and should be
able to
enforce this at a given point.
By extending core classes (and I love to do it BTW) she is taking great
risks.
If you do not agree, that means to me that you are probably a very very
talented designer, but do you not know error prone people like me?

It's far better to think in terms of
> what an object must *do* in your method, rather than to try to consider
> what they *are* in your method. An example might help.
>
> Transaction::Simple has a debug mechanism. It expects an object that can
> respond to #<< for output (and I believe *checks* for it). By default,
> that means that I support String, Array, IO (and most, if not all,
> descendants), and StringIO. I explicitly wanted it this way, whereas if
> I had placed a class check (and make no mistake: most people are
> familiar with statically typed languages and the addition of this will
> make people think of Ruby in terms of static typing),


might be and the way I presented it, for sure, real big mistake of mine.

I would have
> prevented the use of all but the class(es) that I explicitly specified.


So you would not, why should you? There is no static typing, there is
only
the possibility of *early* renforcement of contract.
It might be a bad idea anyway, but I did not reach you. This is
completely
clear from your very elaborate answer, which I appreciate.
Look at it like this when we ask to check for certain conditions at
certain
points by means of assertions we have normally good reason to do so,
right???
I belive that the moment when a message is sent is often the ideal
moment to
reinforce such constraints.
def foo(x : {|para| %r{Robert is a real egghead} =~ x})
I can of course write that on my own in the next line, but it would just
be
against my laziness

Maybe it is a feeling that I need help for my shortcomings as a
programmer.
I thaught "contract enforcing mechanisms" might allow for an easier way
to
program defensively.
But I might be caught in too old paradigms, I really feel that you feel
this
way and I will take it quite seriously.

Unless you have a *damn* good reason to restrict a method to a
> particular class, you shouldn't be doing any sort of checking at all
> that way. Checking on method presence (e.g., #respond_to?) is more
> useful (but only partially so; you should check the #arity of a method),
> but even that fails if the person forgets to implement #respond_to? when
> they've implemented #method_missing. It's also an extra run-time check
> that, well, Ruby already does for you.


Meta programming might ruin it, singleton methods might ruin it, we
should
use only final classes and methods as in Java ;)
Now you see I understand this, your reaction, it might be a very sound
one.

Make no mistake: I'm not afraid of static typing. I just think that it's
> useless in the context of real software development.


Agreed

I've been
> developing software for ... a long time. Professionally a little less
> than that. ;) I really *cannot* think of a time when I found that static
> typing did anything except get in my way.


And you never used  assertions  neither  as you stated  above?

> one reason I'm so consistently opposed to the Eater Nil that is
> periodically proposed: it changes the behaviour to silently fail instead
> of noisily fail if I get something I'm not supposed to (usually a nil;
> in the stuff that I've developed, you won't typically get a Real Object
> that doesn't work).


I take this point at 100%, I might be biased by bad design methods.

> > the opportunity.
>
> It's exceedingly ugly. It's also no better, in implementation terms,
> than placing the contract enforcement as lines of code at the top of the
> method. Except that the latter is clearer, explicit, and infinitely more
> maintainable than writing a miniprogram in the parameter list. (And can
> easily be extracted to a unit test where that sort of thing probably
> belongs in most Ruby code.)


Well I can live with this statement, I was quite aggressive too ;)

Don't get me wrong: there are times when specifying a type is necessary.
> complex validation, which really does underscore my point that this
> behaviour belongs in the method itself. Maybe we can have precondition
> and postcondition sections of methods, but putting all this in the
> parameter list is ugly and nonsensical.)


Well no, that was not intended , please remember that I *never* wanted
any
obligation to check.
I wanted a tool, and probably it is not useful, you quite convinced me.

> I really fail to see why this is inhibiting the language. Such
> > programs fail explicitly and early, which is better (I claim) than
> > maybe failing later or just not behaving as expected.
>
> Ah. That's where you're wrong: such programs would not fail any earlier
> than they do now. The singular "advantage" to statically typed languages
> is that they fail during the compile stage if there's a mismatch. Your
> method still won't fail until it is called.


That was intened like this, it would fail when called and not maybe
three
stack levels later, but as you said already, I can  enforce the contract
myself on crucial points.

-austin
> --
> Austin Ziegler * halostatue@gmail.com
>                * Alternate: austin@halostatue.ca
>

Thanks a lot for your precious time taken.

Robert

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-04-02 16:01
(Received via mailing list)
On Apr 2, 2006, at 9:29 AM, Austin Ziegler wrote:
> Ruby
> it's often far more efficient to ensure that the caller doesn't
> screw up
> instead of the callee doing checks ...

If I remember correctly from _Object Oriented Software Engineering_,
Betrand Meyer specifically talks about how when pre-conditions fail, it
is the *caller* that has violated the contract.  When a program is
written
correctly (i.e., without bugs) pre-condition testing is completely
superfluous
at run-time.  I think the Eiffel compilers even have a switch to turn-
off
run-time pre-condition testing.

I'd rather see the support for pre-conditions and testing within the
context of the development environment rather than burdening the run-
time
environment.  The use of annotations along with smart text editors and
test-case generators might be useful.

Gary Wright
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2006-04-02 16:14
(Received via mailing list)
On 4/2/06, gwtmp01@mac.com <gwtmp01@mac.com> wrote:
> > that don't behave the way you want those objects to behave, then
> written
> test-case generators might be useful.
>
> Gary Wright


Interesting points, please be aware though, that the runtime
environement
would not be burdened at all.
I was just talking about alternative syntax for things one can do
already
The Eifel idea is intriguing though.
One could run with a switch to execute pre_condition assertions

A have difficulties evaluating the role of "unit testing" in these
conceptual idea of checking conditions.

Maybe we should see programs incomplete without there test suits.

As this strikes me as a sound approach not followed often enough it
might
not be possible all the time and is not really part of the Ruby concept.

Cheers
Robert




--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
31ab75f7ddda241830659630746cdd3a?d=identicon&s=25 Austin Ziegler (Guest)
on 2006-04-02 16:26
(Received via mailing list)
On 4/2/06, Robert Dober <robert.dober@gmail.com> wrote:
> On 4/2/06, Austin Ziegler <halostatue@gmail.com> wrote:
[...]
>> In Ruby, at least, inheritance is not a guarantee of a contract (even on
>> objects derived from core classes).
> That is a very delicate point too, I strongly feel that  a developper
> should *know* what kind of protocol an object is implementing and
> should be able to enforce this at a given point. By extending core
> classes (and I love to do it BTW) she is taking great risks. If you do
> not agree, that means to me that you are probably a very very talented
> designer, but do you not know error prone people like me?

By and large, I don't modify core classes except with modules, and in
libraries that I have released I try to make those modifications
separately loadable.

>> Transaction::Simple has a debug mechanism. It expects an object that
>> can respond to #<< for output (and I believe *checks* for it). By
>> default, that means that I support String, Array, IO (and most, if
>> not all, descendants), and StringIO. I explicitly wanted it this way,
>> whereas if I had placed a class check (and make no mistake: most
>> people are familiar with statically typed languages and the addition
>> of this will make people think of Ruby in terms of static typing),
> might be and the way I presented it, for sure, real big mistake of
> mine.

Not just the way you've presented it. Pragmatic experience. A lot of
people are *comfortable* with the security blanket static typing and
they'll see any parameter-level checking mechanism -- especially one
that shorthands as you've suggested -- as a way to get static typing in
Ruby.

>> I would have prevented the use of all but the class(es) that I
>> explicitly specified.
> So you would not, why should you? There is no static typing, there is
> only the possibility of *early* renforcement of contract.

> It might be a bad idea anyway, but I did not reach you. This is
> completely clear from your very elaborate answer, which I appreciate.
> Look at it like this when we ask to check for certain conditions at
> certain points by means of assertions we have normally good reason to
> do so, right???

> I belive that the moment when a message is sent is often the ideal
> moment to reinforce such constraints.

>	def foo(x : {|para| %r{Robert is a real egghead} =~ x})

> I can of course write that on my own in the next line, but it would
> just be against my laziness

But the block you've described is hard to read in the context of the
parameters (adding a lot of extra garbage in a parameter declaration is
really ugly and reduces readability). Maybe:

  def foo(x) : { |x| %r{Another way} =~ x}
	...
  end

I donno, though. I still don't like it and don't think that it's any
more useful than putting the assertion in the code. The only real
benefit would be if rdoc could be modified to detect such assertions,
and that could be done by convention:

  def foo(x)
	raise unless %r{Another way} =~ x # :precond:
	...
  end

Such things could then be added to documentation automatically.

> Maybe it is a feeling that I need help for my shortcomings as a
> programmer. I thaught "contract enforcing mechanisms" might allow for
> an easier way to program defensively. But I might be caught in too old
> paradigms, I really feel that you feel this way and I will take it
> quite seriously.

Enforcing contracts isn't a bad thing. It's just often important to
remember that Ruby does a lot of that enforcement for you and not
overthink it.

[...]

>> I've been developing software for ... a long time. Professionally a
>> little less than that. ;) I really *cannot* think of a time when I
>> found that static typing did anything except get in my way.
> And you never used assertions neither as you stated above?

I personally rarely use assert() in my C++ code; my coworkers use it a
bit more often, but my C++ is now strongly informed by my Ruby.

[...]

>> It's exceedingly ugly. It's also no better, in implementation terms,
>> than placing the contract enforcement as lines of code at the top of
>> the method. Except that the latter is clearer, explicit, and
>> infinitely more maintainable than writing a miniprogram in the
>> parameter list. (And can easily be extracted to a unit test where
>> that sort of thing probably belongs in most Ruby code.)
> Well I can live with this statement, I was quite aggressive too ;)

Part of what I like about Ruby is its aesthetics. I'm a little defensive
about things that I think reduce the aesthetics. (This includes a
proposal by Matz for Ruby 2.0 with the -> mechanism as an alternative to
lambda.)

> useful, you quite convinced me.
Actually, I wouldn't be opposed to something like:

  def foo(x)
	precond do
	  # the precond must return a true value or an exception is raised
	end
	# implementation
	postcond do
	  # the postcond must return a true value or an exception is raised
	end
  end

The thing is, that doesn't require implementation in Ruby's core or
changes to the syntax. But having something to do that *formally* in the
standard library might not be bad.

-austin
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-04-02 16:26
(Received via mailing list)
On Apr 2, 2006, at 10:12 AM, Robert Dober wrote:
> Interesting points, please be aware though, that the runtime
> environement
> would not be burdened at all.
I don't follow.  Wouldn't each method call involve executing the pre-
condition tests?

> As this strikes me as a sound approach not followed often enough it
> might
> not be possible all the time and is not really part of the Ruby
> concept.

It may not be part of the Ruby language but I've found that the Ruby
culture certainly
encourages automated testing as an integral part of program development.


Gary Wright
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2006-04-02 16:38
(Received via mailing list)
On 4/2/06, gwtmp01@mac.com <gwtmp01@mac.com> wrote:
>
>
> On Apr 2, 2006, at 10:12 AM, Robert Dober wrote:
> > Interesting points, please be aware though, that the runtime
> > environement
> > would not be burdened at all.
> I don't follow.  Wouldn't each method call involve executing the pre-
> condition tests?


No it would not unless specified, but look at the nice idea Austin has
given
us above, makes it much clearer.

* precond and postcon blocks.

Wouldn't that allow for great possibilities with rdoc and switching them
on/off with switches.
That might be a great opportunity with RITE as we can create byte code
without the conditions after testing :)
And of course if you do not specify them they would not burden anything!


> As this strikes me as a sound approach not followed often enough it
> > might
> > not be possible all the time and is not really part of the Ruby
> > concept.
>
> It may not be part of the Ruby language but I've found that the Ruby
> culture certainly
> encourages automated testing as an integral part of program development.


And I thaught it might encourage defensive programming - but had quite a
limited idea.
Your post and Austin's - who has taken a lot of time on this one, ty
again,
  have braught up some
good ideas, my approval is not enough of course.

Gary Wright


Ty both for your enlightement.

Cheers
Robert




--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-04-02 17:06
(Received via mailing list)
On Apr 2, 2006, at 10:36 AM, Robert Dober wrote:
>
> * precond and postcon blocks.
>
> Wouldn't that allow for great possibilities with rdoc and switching
> them
> on/off with switches.

Just to clarify.  I think there is great value in programming-by-
contract.
Being able to specify pre and post conditions (and class invariants)
in the same language as the code is great also.  Unit testing is good.
A way to combine all these things in a development environment would
be great.
If this approach kept to the spirit of the Ruby syntax/style; didn't
incur any run-time costs; and was integrated into the documentation,
editing, and
testing tools it would be wonderful.

The part that rubs me wrong is the idea that the 'production' code
needs to
also run all those pre-condition tests on each and every method call
and the
tendency to *over* specify the pre-conditions that interfere with the
flexibility
of a dynamic language (duck typing).  Over-specified runtime pre-
conditions bake in
extra assumptions that make the code more rigid than necessary (i.e.
Austin's
example of expecting '<<' but nothing more).


Gary Wright
5dfb03e2e567dcbe857efa96f998d499?d=identicon&s=25 gabriele renzi (Guest)
on 2006-04-02 17:26
(Received via mailing list)
gwtmp01@mac.com ha scritto:

> Just to clarify.  I think there is great value in programming-by- contract.
> Being able to specify pre and post conditions (and class invariants)
> in the same language as the code is great also.  Unit testing is good.
> A way to combine all these things in a development environment would  be
> great.

maybe interesting for you:
http://rubyforge.org/projects/ruby-contract/
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2006-04-02 17:29
(Received via mailing list)
On 4/2/06, gwtmp01@mac.com <gwtmp01@mac.com> wrote:
> > No it would not unless specified, but look at the nice idea Austin
> contract.
> needs to
> also run all those pre-condition tests on each and every method call
> and the


It defenitely does not when we compile to byte code in Ruby2.0 :)

tendency to *over* specify the pre-conditions that interfere with the
> flexibility
> of a dynamic language (duck typing).  Over-specified runtime pre-
> conditions bake in
> extra assumptions that make the code more rigid than necessary (i.e.
> Austin's
> example of expecting '<<' but nothing more).


Well can you think of any tool that cannot be abused?


Gary Wright
>
>
>


--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 unknown (Guest)
on 2006-04-02 18:09
(Received via mailing list)
On Apr 2, 2006, at 11:26 AM, Robert Dober wrote:
> Well can you think of any tool that cannot be abused?

Well no, but I think the back and forth on this topic is
all about what should be considered 'abuse'.

So on one side we have folks who want to raise an exception when
an argument isn't an instance of String and on the other side we
have folks who just call to_s and let Ruby raise an exception if
the object doesn't implement to_s.

In either case you could codify the expectation as a pre-condition and
there are any number of ways to do that with Ruby. But having a
pre-condition mechanism doesn't answer the question:
What criteria should be used when designing pre-conditions?

Gary Wright
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2006-04-02 19:17
(Received via mailing list)
[David]
No: the definition of the method dictates the functionality of the
method.  That can vary from one instance to another, even within a
class.  It often doesn't; but because it *can*, one can view the case
where two instances of a class behave the same way as a special case of
the case where they don't.
[/David]

A fair point althouhg not exactly true. When you define a singleton
method you are quite literally giving an object a new Class, the
original of which becomes the superclass of the new one. One assumes of
course, as we all do and must, that a subclass essentially obeys the
same contract as it's anscestor. Not that it has to of course, but in
general we must in order to gain from the whole OOP methodology.

A String and an Integer, for instance, are very different things. So
when I specify a parameter should be an an Integer, say, I mean that it
should be quite like one of those things, so much so that it should be
a sublcass of it or have a coercability for becoming so, otherwise
don't waste time trying. Just b/c some other object might repsond to
all the same methods I end up using doesn't mean much --poeple just
don't think that way. I've creted my method to deal with Integer's
that's what I designed it to do. You want to send it a Watchamacallit?
Why? You really think it's going to work? Do you know enough about the
method I wrote to think that using it with Watchamcallit's will be all
that beneficial? If a Watchamacallit isn't Integery enough to be a
subclass of one or be coerced into one, what makes you think it SHOULD
work? What if you change Watchamacallit later on? What if my mehtod
changes later on? Integer's not likely to change that's what I'm
depending on. This Integer contract may not be perfect, but it relative
dependency is intrumental to the construction of my software. There are
no gaurantee's whatsoever for Watchamacallits.

I think duck typing is great and all, but it's one of those things that
plays better in theory than it actually does in practice.

T.
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2006-04-02 20:40
(Received via mailing list)
From: "Trans" <transfire@gmail.com>
>
> I've creted my method to deal with Integer's
> that's what I designed it to do. You want to send it a Watchamacallit?
> Why? You really think it's going to work? Do you know enough about the
> method I wrote to think that using it with Watchamcallit's will be all
> that beneficial?

I don't see why you would need to bear the burden of worrying
about this.  Let it be my problem, if I feel the need to use
your library in a way you hadn't anticipated.  :)

> If a Watchamacallit isn't Integery enough to be a
> subclass of one or be coerced into one, what makes you think it SHOULD
> work? What if you change Watchamacallit later on? What if my mehtod
> changes later on?

Hmm... This is starting to remind me of public vs. private
methods.  Ruby lets me call a private method on one of your
classes, but I have to do so explicitly - and if your class
internals change later on and my call to that private method
breaks, I won't be surprised.  I took the risk deliberately.

Maybe if parameter types could be specified and enforced in
some way where I, the library user, would have a means of
calling the method that would bypass those checks?  So that,
most of the time, I pass in an Integer and everyone's happy.
But if I decide that passing in a Watchamacallit best meets
my needs, then there should be a way to call your method and
bypass the type checks - even if I have to be explicit about
it.

I guess what I'm saying is IF there were typed parameters,
I think there should be a way around the checks, similar to
how we can call private methods when we really need to.


Regards,

Bill
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2006-04-02 22:11
(Received via mailing list)
Bill Kelly wrote:
> your library in a way you hadn't anticipated.  :)
> breaks, I won't be surprised.  I took the risk deliberately.
> I guess what I'm saying is IF there were typed parameters,
> I think there should be a way around the checks, similar to
> how we can call private methods when we really need to.

That's a fair assessment. And really it's probably enough to do:

  class Watchamacallit
    def to_int ; self ; end
  end

Wouldn't that be a fair way of saying somthings Integery?

I also would like to point out that this idea of contract parameters
isn't just a means of code reliability. People make good point when
they argue that unit tests can go along way toward  mooting this need
while improving production performance. But, they are also useful for
dividing up code base on parametric concerns. To be able to do

  def foo( x : String )
    ...
  end

  def foo( x : Int )
    ...
  end

seems to me a much more readible and versitile way of handling the
cases, irregardless of any contractual beneifits.

T.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-04-02 22:23
(Received via mailing list)
On Mon, 3 Apr 2006, Trans wrote:

>  def foo( x : String )
>    ...
>  end
>
>  def foo( x : Int )
>    ...
>  end
>
> seems to me a much more readible and versitile way of handling the
> cases, irregardless of any contractual beneifits.

not to mention that rdoc can then generate a doc block for 'what foo
does with
ints' and 'what foo does with strings'.  with duck typing these get
rolled
into one block and it's strictly up to the comments to reveal the
distiction.

2cts.

-a
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2006-04-02 22:48
(Received via mailing list)
ara.t.howard@noaa.gov wrote:
>> seems to me a much more readible and versitile way of handling the
>> cases, irregardless of any contractual beneifits.
>
> not to mention that rdoc can then generate a doc block for 'what foo
> does with
> ints' and 'what foo does with strings'.  with duck typing these get rolled
> into one block and it's strictly up to the comments to reveal the
> distiction.

If foo is implemented in duck type style, should it even say what it
does with int, string, etc.? Isn't it better for the foo comment to say
something like "#foo doesn't care what x is, except that when you
#frobble it, the result is something that can #zurgle."

But, terminology aside, I agree... if, as sometimes happens, you just
*have* to switch on the class of x in foo, it would be nice to make it
explicit in a way that rdoc can understand. This can be done crudely
today, by calling a different method (foo_int, foo_string) in each of
the _when_ clauses.

Hey, maybe rdoc could be modified to look for 'case x', if an argument
is x, and extract comments from before each _when_ clause. That is not
totally unprecedented, since rdoc looks for 'yield result' inside the
def..end.
D812408537ac3a0fa2fec96eb8811559?d=identicon&s=25 John Carter (Guest)
on 2006-04-02 23:06
(Received via mailing list)
On Sun, 2 Apr 2006, Robert Dober wrote:

>            assert_type clever, String
>           assert_type  smart, Hash
>          assert_type  stuoid, Boolean
> ....
> def cool( clever : String, smart : Hash, stupid : Boolean )
>
> and of course
> def x(y)  would be equivalent to def(x : Object )

Howabout what I do..


def never_saw_a_better_method( clever, smart, stupid )
   clever.static_type_check String
   smart.quacks_like :each_pair
   stupid.poymorphic_type_check SomeBaseClass
end


# Abstract base class for all the type check exceptions
class TypeCheckException  < Exception
end

# This exception is thrown in event of a method being invoked with an
# object of the wrong duck type.
class DuckTypingException < TypeCheckException
end

# This exception is thrown in event of a method being invoked with a
# parameter of of the wrong static type.
class StaticTypeException < TypeCheckException
end

# This exception is thrown in event of a method being invoked with a
# parameter of of the wrong polymorphic type.
class PolymorphicTypeException < TypeCheckException
end


class Object

   # Raise a DuckTypingException unless the object responds to all
symbol.
   def quacks_like( *symbols)
     symbols.each do |symbol|
       raise DuckTypingException, "Duck typing error, expected this
object to respond to :#{symbol}, but found class
#{self.class}\n\t\t#{symbol.inspect}" unless
         respond_to? symbol
     end
   end

   def static_type_check( klass)
     raise StaticTypeException, "Static type check error, expected
object to be exactly class '#{klass}', found
'#{self.class}'\n\t\t#{self.inspect}" unless
       self.class == klass
   end

   def polymorphic_type_check( klass)
     raise PolymorphicTypeException, "Polymorphic type check error,
expected object to be a kind of '#{klass}', found
'#{self.class}'\n\t\t#{self.inspect}" unless
       self.kind_of? klass
   end

end


if $0 == __FILE__ then
   require 'test/unit'

   class TC_Utilities < Test::Unit::TestCase

     def test_utilities
       assert_raise( DuckTypingException) { nil.quacks_like( :call)}
       assert_raise( DuckTypingException) { 1.quacks_like( :+, :call)}
       1.quacks_like( :+, :-, :*)

       assert_raise( StaticTypeException) { nil.static_type_check(
String)}

       assert_raise( PolymorphicTypeException)
{"foo".polymorphic_type_check( Array)}

       begin
         2.static_type_check( String)
       rescue TypeCheckException => details
         puts details
       end
       begin
         2.polymorphic_type_check( String)
       rescue TypeCheckException => details
         puts details
       end
     end

   end


end



John Carter                             Phone : (64)(3) 358 6639
Tait Electronics                        Fax   : (64)(3) 359 4632
PO Box 1645 Christchurch                Email : john.carter@tait.co.nz
New Zealand

Carter's Clarification of Murphy's Law.

"Things only ever go right so that they may go more spectacularly wrong
later."

From this principle, all of life and physics may be deduced.
5dfb03e2e567dcbe857efa96f998d499?d=identicon&s=25 gabriele renzi (Guest)
on 2006-04-02 23:49
(Received via mailing list)
ara.t.howard@noaa.gov ha scritto:
>> seems to me a much more readible and versitile way of handling the
>> cases, irregardless of any contractual beneifits.
>
>
> not to mention that rdoc can then generate a doc block for 'what foo
> does with
> ints' and 'what foo does with strings'.  with duck typing these get rolled
> into one block and it's strictly up to the comments to reveal the
> distiction.

and that you can actually extend the interface, either in a subclass or
in a singleton object or in the original one, withouth the need to acces
the source code or adding a stack of wrappers


> 2cts.

mine, too.
This topic is locked and can not be replied to.