"Reimer Behrends" <behrends / cse.msu.edu> wrote in message news:slrn96vftq.kgf.behrends / allegro.cse.msu.edu... [...] > > It had previously been asserted in the discussion that > > Ruby would have trouble with full blown generic programming > > because of the lack of overloading and and automatic instantiation > > of overloaded functions for the generic parameters. > Yes. This, of course, is wrong. Which is why I was giving a more Hm I think nobody claimed anything like this > complete picture as to how genericity can be viewed as an example of > inheritance, for instance. I would again advise that people familiarize > themselves with, say, Beta's virtual patterns. It should be obvious that > classes in Ruby can do pretty much all that patterns can do. Example: > > class Polynomial < Ring > > def type > nil # Formal type, undefined > end > > # add the usual operations on polynomials here, dependent > # on the result of 'type'. > > end > class ComplexPolynomial < Polynomial > > def type > Complex > end > > end I am not sure why you want to introduce an inheritance ``ComplexPolynomial < Polynomial'' relation? Somebody else might hold the equally valid opinion that the number of variables ``rel_dim'' should determine the inheritance relation. So it is probably best not worry about this at all. Simply introduce a couple of Class attributes like class << Polynomial def coeff # type of base ring end def rel_dim # number of vars end end and nobody is going be pissed. I hold the opinion that there is a general problem with OO that tries to enforce inheritance relation when there isn't a real crying need to do so ... Christoph > Now, you may want to modify this to avoid speed problems (e.g., > computing the function only once and sticking it in a variable, > or using eval/class_eval/etc. to generate an optimized class on > the fly), but the general idea is that in Ruby you can redefine > any aspect of a class, including types, exceptions that are > caught, and whatnot. Put a number of such functions in there, > perhaps encapsulating them in a mixin, and you essentially > have the functionality that are covered by traits. > > [...] > > >To begin with, for the most basic use of generic types, no additional > > >effort is necessary--Array and Hash are obvious examples. > > This was simple just noting something important--a large majority > of generic types simply require that the objects they manipulate > simply respond to certain messages--no additional measures are > needed. Just because C++ or Eiffel as statically typed languages > need the types as parameters doesn't mean the same for Ruby or > Smalltalk. > > > A main idea of the traits technique is that one may bundle > > all of the generic inteface in a kind of proxy class. > > A main idea of the traits technique is that in a compiled language you > somehow have to juggle things around so that the compiler won't > complain. In dynamically typed languages, factory objects will usually > provide the same information that you have elsewhere nicely. If it's > needed at all. > > The big problem in C++ is that you have to determine _at compile time_ a > number of things. In Ruby, first of all, many of these don't need to be > determined. Secondly, there's no real difference between compile time > and runtime in Ruby. So, while C++ template mechanism essentially > provides yet another Turing-complete engine (with the concomitant cost > increase for developing correct compilers and other language tools), > dynamically typed languages can just ignore this. > > What I'm saying here is that most of the tools for generic programming > in C++ are artifacts of the language, not a prerequisite for using the > techniques. > > [...] > > >For more > > >advanced schemes, it may be best to avoid the elaborate and > > >unnecessarily complicated maze of C++ templates and return to simpler > > >approaches. > > > > C++ templates aren't actually complicated, but anyway, that's > > off the point anyway. > > I'm not sure if you've ever thought about the inherent complexity > of implementing the C++ type mechanism completely and correctly in a > compiler? I played around with trying to do a formal specification > in Z a while ago, which was bad enough. In other words, I'm not > saying that a user can't understand it, but that it adds unnecessary > complexity to the language specification and implementation. > > > For instance, the instantion of a parametric type A[X] as > > >A[T], where X is a formal parameter and T a concrete type, can be seen > > >as specialization inheritance from A[X] with X = T. What we need for > > >this to work is to be able to work with types as first class > > >objects--something that C++ can't do, > > > > a) that's not necessary > > True, Eiffel 2 did it without having types as first class objects, but I > was simplifying here (expressing a sufficient, not a necessary > condition). What I basically mean is that having classes as first class > objects (or an equivalent mechanism) eliminates most of the problems. > C++ "solves" the problem by making the template mechanism a small > programming language of its own, where classes _are_ first class > objects--an exercise that would be absolutely pointless in Ruby. > > > b) the traits technique approximates the same thing anyway. > > See above. > > > >but Ruby can. Instantiating formal > > >parameters of generic types is basically constraining a family of > > >objects along one more dimensions. While I believe that somebody > > >mentioned earlier that genericity and inheritance are orthogonal > > >concepts, the opposite is true: generics introduce a classical is-a > > >relation, generally with full substitutivity (modulo the usual > > >covariance issues). > > > > I don't understand which is-a relationship you are talking about here. > > Could you give an example? > > Simple. Let Polynomial[X] be the generic type of polynomials over a > ring. Then we have > > Complex < Field < Ring, > > and thus > > Polynomial[Complex] < Polynomial[X], > where the relation < expresses a subtyping relationship (modulo > covariance issues, which we tend to naturally ignore in Ruby anyway, > since only type theorists tend to get worked up over them). > > > >Instantiating the formal paramaters would then be the > > >equivalent to performining currying on 'initialize'. > > > > Have to ask you again for an example. I know currying > > and initialize, but I'm not sure what your vision is > > here. > > Class Polynomial < Ring > > def initialize(type, data) > @type = type > ... do something with 'data', based on @type ... > end > > # Add usual operations on polynomial here, depending > # on @type. > > end > > Class ComplexPolynomial < Polynomial > > def initialize(data) > super Complex, data > end > > end > > It should also > > >be noted that just because something is part of C++ it should not > > >necessarily be added to another language; in fact, the converse is > > >generally true. > > > > I wasn't advocating that. > > Sorry. I wasn't trying to claim you did. I was just noting in general > that I usually question the wisdom of importing most of the hacks that > are native to C++ into another unsuspecting language. They generally > come with a ridiculous cost in terms of specifying them properly and > implementing them. For instance, while the fact that the grammar of > C++ isn't LR(k) for any k has certainly served to advance the field > of parsing technology (ANTLR, BTYacc), it hasn't made the language > proper commensurately more expressive. > > > Though I have suggested in other posts > > that overloading would be useful in Ruby, but for somewhat different > > reasons. > > Overloading doesn't make sense in the context of Ruby, since it requires > static type declarations as a prerequisite. You are probably referring > to multiple dispatch, which is a feature of a number of other languages > (such as Dylan), but not C++. > > Reimer Behrends