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 inlibraries that I have released I try to make those modificationsseparately 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 ofpeople are *comfortable* with the security blanket static typing andthey'll see any parameter-level checking mechanism -- especially onethat shorthands as you've suggested -- as a way to get static typing inRuby.
>> 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 theparameters (adding a lot of extra garbage in a parameter declaration isreally 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 anymore useful than putting the assertion in the code. The only realbenefit 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 toremember that Ruby does a lot of that enforcement for you and notoverthink 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 abit 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 defensiveabout things that I think reduce the aesthetics. (This includes aproposal by Matz for Ruby 2.0 with the -> mechanism as an alternative tolambda.)
>> (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.
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 orchanges to the syntax. But having something to do that *formally* in thestandard library might not be bad.
-austin--Austin Ziegler * halostatue / gmail.com               * Alternate: austin / halostatue.ca