Reimer Behrends <behrends / cse.msu.edu> wrote: >Josh Stern (jstern / foshay.citilink.com) wrote: >> Reimer Behrends <behrends / cse.msu.edu> wrote: >> >Josh Stern (jstern / foshay.citilink.com) wrote: >> Reimer, you misunderstood the pragmatics of my post. > >Umm, no. But I was simply using it as a jumping-off point to discuss >matters that had been raised througout the thread. If you felt >"targeted", my apologies. >I was simply using this as an opportunity to >go into lecture mode. :) Ok. I think I should apologize for mis-reading. >[...] >> >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. Beyond static typing, there are also large context and cultural differences at work here. C++ analysis often has the subtext that there is a library designer implementing foundation classes that are not to be touched, often irritating other programmers who feel something is missing and/or inheriting too much overhead; Smalltalk has the idea that this great set of foundation classes is given as part of the language/environment itself, often causing splintering, big need to recover costs of language implementation, etc; while Ruby, so far, is happy with the idea of everyone redefining whatever merrily as they go, which might prove, uh, interesting in a long-running, multi-person project. Point being that a bunch of the difference is not just in the language itself but what has been deemed acceptable in terms of givens, overhead, speed, etc. >> 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. Disagree. First, because it's not true, and second, even if it was true, it makes a big difference on which side of the interface the specifications have been made. Traits allow the specifcation on the caller side. >The big problem in C++ is that you have to determine _at compile time_ a >number of things. That's a huge problem if these things are not known at compile time. And that's a key reason why a static language often needs to be supplemented with some sort of scripting setup in another language. I've implied elsewhere in this thread that two of the biggest weaknesses in a language like C++ are this lack of dynamism and also the lack of support for converting between textual represenations and internal/excutable ones. But I'm not sure what else you are getting at. Bad declaration syntax? Lack of library support for heterogenous containers? >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. I believe that there are generic programming techniques in much the same sense as there are object-oriented programming techniques which are described at a level that crosses language boundaries. >[...] >> >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 Of course I know about the complexity of implementing a C++ compiler (noted elsewhere in this thread that no major compilers implement all template linkage features), but I assumed you were talking about complexity for the language user above. >> 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, What you describe just sounds like regular template instantiation and specialization. It's normal in C++. When I wrote the following: >> b) the traits technique approximates the same thing anyway. >See above. I just meant it to refer to the bit about passing types as parameters. It isn't needed for the example. >> >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). This instatiation in C++ does not necessarily create subtypes in this way; it wouldn't in the example; Polynomial[X] is an incomplete type, outside of the type system, not a parent. >> 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++. Well, I meant both - a) overloading based on function signatures (defined as either an optional feature extending the language or a meta-programming function written in current Ruby (though for this and other reasons, it would be nice to extend Ruby to be able to get the syntax tree for a Proc), and possibly b) what would be called multiple dispatch in a language with both static and dynamic types. -= Josh