Typed Parameters

On 4/2/06, Robert D. [email protected] wrote:

On 4/2/06, Austin Z. [email protected] 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. :wink: 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 :wink:

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

On 4/2/06, [email protected] [email protected] wrote:

On Apr 2, 2006, at 10:12 AM, Robert D. 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 :slight_smile:
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 W.

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

On Apr 2, 2006, at 10:36 AM, Robert D. 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 W.

On Apr 2, 2006, at 10:12 AM, Robert D. 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 W.

[email protected] 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/

On Apr 2, 2006, at 11:26 AM, Robert D. 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 W.

On 4/2/06, [email protected] [email protected] 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 :slight_smile:

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 W.


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

From: “Trans” [email protected]

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. :slight_smile:

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

Bill K. wrote:

your library in a way you hadn’t anticipated. :slight_smile:
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.

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

[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.

[email protected] 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.

On Sun, 2 Apr 2006, Robert D. 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 C. Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : [email protected]
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.

[email protected] 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 forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs