>> 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)
> 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?
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).
I take this point at 100%, I might be biased by bad design methods.
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.)
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.
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.)
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
···
On 4/2/06, Austin Ziegler <halostatue@gmail.com> wrote:
On 4/2/06, Robert Dober <robert.dober@gmail.com> wrote:
> On 4/2/06, Daniel Nugent <nugend@gmail.com> wrote:
--
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