osdir.com
mailing list archive

Subject: Modeling multiple inheritance - msg#00112

List: lang.haskell.cafe

Date: Prev Next Index Thread: Prev Next Index

Brandon Michael Moore wrote:

> So I defined a class to model the inheritance relationships

> class SubType super sub | sub -> super where
> upCast :: sub -> super

> Now I can define a default instance of HasFooMethod:
> instance (HasFooMethod super args result,
> SubClass super sub) =>
> HasFooMethod sub args result where
> foo sub args = foo (upCast sub) args

> This will propagate foo methods down the inheritance hierarcy. If a new
> class C is derived from A, I just need to say

> One problem is that the subclass relationship needs the functional
> dependency

> Does anyone know of clever solutions that would model multiple inheritance
> while preserving the functional dependencies (unsafe compiler flags are
> fine too), or ways to reduce the pain of overloading resolution without
> the functional dependency?

Yes. The code included. The solution is trivial: in case of a multiple
inheritance, a class has a _sequence_ of superclasses rather than a
single superclass. Like

instance SubClass (Object,()) ClassA
instance SubClass (Object,()) ClassB

-- Multiple inheritance (including the diamond!)
instance SubClass (ClassA,(ClassB,())) ClassC
instance SubClass (ClassA,(ClassB,(ClassC,()))) ClassD

And we need some intelligence to traverse the sequence. But even a
computer can do that.

I would like to propose a different solution: a dual of
typeclasses in the value domain. Function foo is just a regular
function

foo:: Object -> Int -> Int
foo x y = y

We then need a class MApplicable fn args result with a method
mapply. The trick is that the method should take any object of a type
castable and cast it to the type of the first argument of fn. The cast
can be made safe and statically checkable, using the type
heap. Actually, we can use the type heap to model the dispatch table
(whose rows are functions and columns are object/classes). Given a
function and an object, we can search in many way for the applicable
combination.

And now, the code for the solution that works.
Compiler flags:
-fglasgow-exts -fallow-overlapping-instances -fallow-undecidable-instances

data Object = Object
data ClassA = ClassA
data ClassB = ClassB
data ClassC = ClassC
data ClassD = ClassD

class SubClass super sub | sub -> super where
upCast :: sub -> super

instance SubClass (Object,()) ClassA
instance SubClass (Object,()) ClassB
-- Multiple inheritance (including the diamond!)
instance SubClass (ClassA,(ClassB,())) ClassC
instance SubClass (ClassA,(ClassB,(ClassC,()))) ClassD

class HasFooMethod cls args result where
foo :: cls -> args -> result

instance (SubClass supers sub,
HasFooMethod supers args result)
=> HasFooMethod sub args result where
foo obj args = foo (upCast obj) args

instance (HasFooMethod cls args result) => HasFooMethod (cls,()) args result
where
foo (x,()) = foo x

instance (HasFooMethod cls args result) => HasFooMethod (x,cls) args result
where
foo (x,y) = foo y

instance HasFooMethod Object Int Int where
foo _ x = x

test1::Int = foo Object (1::Int)
test2::Int = foo ClassA (2::Int)
test3::Int = foo ClassD (3::Int)

-- Likewise for another method:

class HasBarMethod cls args result where
bar :: cls -> args -> result

instance (SubClass supers sub,
HasBarMethod supers args result)
=> HasBarMethod sub args result where
bar obj args = bar (upCast obj) args

instance (HasBarMethod cls args result) => HasBarMethod (cls,()) args result
where
bar (x,()) = bar x

instance (HasBarMethod cls args result) => HasBarMethod (x,cls) args result
where
bar (x,y) = bar y

instance HasBarMethod ClassB Bool Bool where
bar _ x = x

test4::Bool = bar ClassB True
test5::Bool = bar ClassC True
test6::Bool = bar ClassD True


Was this page helpful?
Yes No
Thread at a glance:

Previous Message by Date: click to view message preview

Re: lexer puzzle

Note I've replied to haskell-cafe. This post is a bit chatty and low on solid answers. On Thu, 25 Sep 2003, Sean L. Palmer wrote: > > >>A... should be split into "A.." and "." > > >I found a compromise: let's make it a lexing error! :-) > > At least that agrees with what some Haskell compilers implement. No > > current Haskell compiler/interpreter agrees with what the report seems > > to say, that is that "A..." should be lexed as the two tokens "A.." and > > ".", and similarly, "A.where" should be lexed as "A.wher" followed by "e". > > Hi. I'm really new to Haskell, just learning it, and I must say I'm pretty > overwhelmed by the large variety of constructs. (=>, <-, \ to name a few) Would that be \ as in TREX row variable polymorphism? Just remember most operators are just library functions. It's only =, ->, =>, <-, :: that are really part of the language, and {,},; for grouping. Did I miss any? > > But I'm just writing this to let you guys know (surely you know this > already) that anyone from a C/C++/Java/Delphi background is going to > completely misunderstand the meaning of A.anything in Haskell... it's > completely nonintuitive to people with my background. I kinda like dot > notation because it ties together the symbols visually, for instance > "myrec.myfield" is more of a unit than "myrec myfield". It stays together > better when surrounded by other code, and would result in fewer parenthesis > necessary. A Python programmer would understand instantly: Python uses exactly the same syntax for module access, though Python modules are usually in lowercase. It also seems to be very much in the spirit of "access a member of this object" of an OO language. Or was that supposed to be composition of a constructor with a function, A . f? Function composition, and higher order functions in general are likely to confuse an imperative programmer, but I think there isn't much syntax can do there. Or are you talking about the field access syntax? Maybe the problem is that dot has two to five different meanings, function composition, naming module members, building hierarchial module names, being a decimal point, and making elipses, and is commonly used for yet another purpose in OO languages. > Haskell to me seems to be a great language with a syntax problem, and a bad > case of too many ways to do the same thing; thus every programmer does > things their own way and it's difficult to grasp the language by looking at > various programs, since they're all so very different. As a small example, > there's 'let' vs. 'where'. Maybe a bit of pruning would be in order. Do you mean the syntax is bad in places? Haskell is the cleanest language I know of, but I'm sure it has some grungy bits. I've had problems with unary minus (can't slice binary minus), and precedence of with irrefuatble patterns and type ascription. I would be happy for any confusing syntax to be improved. Any good ideas? Syntax change is a possibility: do notation is a relatively recent addition, and arrow syntax is in the works. I think you might instead mean the syntax cuts down our market share because it isn't like common (C derived) languages. I don't think Haskell could borrow any more syntax from C without actually making the language worse. It's a problem, but not with the syntax. If someone is so solidly into a C++/Java/OO mindset that the syntax would be a problem, the semantics would probably be even more of a problem. I would suggest Python if Haskell was too much of a jump for someone. It's still OO, but it encourages more flexible and interesting programs, and you don't have to live in a Java type system. Plus, it has more libraries, bindings, and PR, so it's easier to get permission to use it in a company. If someone is used to Python's layout rule and lack of type signatures, and gets their head around some of the fun you can have dynamically picking which members of an object to access, assigning to __dict__ and so on, then Haskell should be much less of a jump in syntax, and less imposing in semantics. > That said, I still think it looks more promising than any other language > I've looked at that actually is being actively used and maintained and has a > decent installed base and good cross platform support. So I will learn it. > I just wish the transition was easier and that it took less time to learn. > ;) > > Sean I learned Haskell from the "gentle introduction". It seemed gentle enough to me but others disagree, so I'm probably not the best for advice for the raw beginner. If you are interested in learning about monads though, Jeff Newbern's monad tutorial seems accessible and as complete as anything this side of Phil Wadler's paper. I hope learning Haskell goes well. Brandon

Next Message by Date: click to view message preview

Re: lexer puzzle

Brandon Michael Moore <brandon@xxxxxxxxxxxxxxx> writes: > Or was that supposed to be composition of a constructor with a function, A > . f? Function composition, and higher order functions in general are > likely to confuse an imperative programmer, but I think there isn't much > syntax can do there. I think there is a problem with too much overloaded syntax. Perhaps it is time to put non-ASCII characters to good use? For instance, function composition could use the degree sign: ° and leave the . for module qualification. Template Haskell could use double-angle quotation marks: « » and the section sign: § and avoid clashing with list comprehensions and the function application operator. Implicit parameters could use an inverted question mark: ¿ And so on, just look for places where the semantics depend on spaces in the right (or wrong) place. -kzm -- If I haven't seen further, it is by standing in the footprints of giants

Previous Message by Thread: click to view message preview

Re: Modeling multiple inheritance

On Thu, 25 Sep 2003 ozone@xxxxxxxxxxxxxxxx wrote: > On 25/09/2003, at 7:22 AM, Brandon Michael Moore wrote: > > > I'm trying to build a nicer interface over the one generated by > > jvm-bridge. I'm using fancy type classes to remove the need to mangle > > method names. I would like methods to be automatcially inherited, > > following an inheritance hierarcy defined with another set of type > > classes. > ... > > Hi Brandon, it looks like the way that you're modelling inheritance and > OO-style overloading is basically the same way that I did in my thesis: > > http://www.algorithm.com.au/mocha > > The actual implementation of the thesis will be up in CVS in ~24 hours, > I'm just waiting from an email back from the people I'm getting it > hosted with. > > If you want a quick run-down on how I did the OO-style overloading > without delving into the paper, let me know and I'll post a quick > summary. I've only skimmed your email, but I think that the problem > you're having with interfaces is solved with the way I'm modelling OO > overloading and class inheritance. Thanks. I think I could use the summary. I already found and skimmed your thesis, and I don't think it gives me exactly what I want. All you do in chapter 3 is represent a multiple inheritance hierarcy. I want default instances that will propagate method definitions along the hierarcy. I'm not sure that's possible though. I want something like this: data Object data ClassA data ClassB data ClassC class SubClass super sub <???> instance SubClass Object ClassA instance SubClass Object ClassB instance SubClass ClassA ClassC instance SubClass ClassB ClassC class HasFooMethod cls args result <??> foo :: cls -> args -> result instance SubClass super sub, HasFooMethod super args result ,??? => HasFooMethod sub args result where foo obj args = foo (upCast obj) args instance HasFooMethod Object int int where foo = id (now all four classes have a foo method) Brandon

Next Message by Thread: click to view message preview

Re: Modeling multiple inheritance

On Thu, 25 Sep 2003 oleg@xxxxxxxxx wrote: > > Brandon Michael Moore wrote: > > > So I defined a class to model the inheritance relationships > > > class SubType super sub | sub -> super where > > upCast :: sub -> super > > > Now I can define a default instance of HasFooMethod: > > instance (HasFooMethod super args result, > > SubClass super sub) => > > HasFooMethod sub args result where > > foo sub args = foo (upCast sub) args > > > This will propagate foo methods down the inheritance hierarcy. If a new > > class C is derived from A, I just need to say > > > One problem is that the subclass relationship needs the functional > > dependency > > > Does anyone know of clever solutions that would model multiple inheritance > > while preserving the functional dependencies (unsafe compiler flags are > > fine too), or ways to reduce the pain of overloading resolution without > > the functional dependency? > > Yes. The code included. The solution is trivial: in case of a multiple > inheritance, a class has a _sequence_ of superclasses rather than a > single superclass. Like > > instance SubClass (Object,()) ClassA > instance SubClass (Object,()) ClassB > > -- Multiple inheritance (including the diamond!) > instance SubClass (ClassA,(ClassB,())) ClassC > instance SubClass (ClassA,(ClassB,(ClassC,()))) ClassD > > And we need some intelligence to traverse the sequence. But even a > computer can do that. That should solve my problem. Putting all the superclasses in a tuple should work. I'm worried about large class hierarchies. If it works on the java.* classes I should be fine. Have you used this approach before? I'm worried about compile time, runtime costs from the casts (hopefully they compile out), and maybe exceeding maximum stack depth in context reduction. This is a clever solution. I like it. Now, is anyone up to encoding the Dylan MRO in Haskell type classes? ;) > I would like to propose a different solution: a dual of > typeclasses in the value domain. Function foo is just a regular > function > > foo:: Object -> Int -> Int > foo x y = y > > We then need a class MApplicable fn args result with a method > mapply. The trick is that the method should take any object of a type > castable and cast it to the type of the first argument of fn. The cast > can be made safe and statically checkable, using the type > heap. Actually, we can use the type heap to model the dispatch table > (whose rows are functions and columns are object/classes). Given a > function and an object, we can search in many way for the applicable > combination. What type heap? It sounds like you are talking about information from an OO runtime, or are you talking about the collection of instances. I tried a system where method names were also represented by data types, but without your solution for multiple inheritance I couldn't get the implementation inheritance I wanted. How would you implement this dispatch table? What are the advantages of this approach over the type class encoding? I'm worried that generating bindings would be a problem if the dispatch table needs to be a monolithic value with a very interesting type in some file. Brandon > And now, the code for the solution that works. > Compiler flags: > -fglasgow-exts -fallow-overlapping-instances -fallow-undecidable-instances > > data Object = Object > data ClassA = ClassA > data ClassB = ClassB > data ClassC = ClassC > data ClassD = ClassD > > class SubClass super sub | sub -> super where > upCast :: sub -> super > > instance SubClass (Object,()) ClassA > instance SubClass (Object,()) ClassB > -- Multiple inheritance (including the diamond!) > instance SubClass (ClassA,(ClassB,())) ClassC > instance SubClass (ClassA,(ClassB,(ClassC,()))) ClassD > > class HasFooMethod cls args result where > foo :: cls -> args -> result > > instance (SubClass supers sub, > HasFooMethod supers args result) > => HasFooMethod sub args result where > foo obj args = foo (upCast obj) args > > instance (HasFooMethod cls args result) => HasFooMethod (cls,()) args result > where > foo (x,()) = foo x > > instance (HasFooMethod cls args result) => HasFooMethod (x,cls) args result > where > foo (x,y) = foo y > > instance HasFooMethod Object Int Int where > foo _ x = x > > test1::Int = foo Object (1::Int) > test2::Int = foo ClassA (2::Int) > test3::Int = foo ClassD (3::Int) > > -- Likewise for another method: > > class HasBarMethod cls args result where > bar :: cls -> args -> result > > instance (SubClass supers sub, > HasBarMethod supers args result) > => HasBarMethod sub args result where > bar obj args = bar (upCast obj) args > > instance (HasBarMethod cls args result) => HasBarMethod (cls,()) args result > where > bar (x,()) = bar x > > instance (HasBarMethod cls args result) => HasBarMethod (x,cls) args result > where > bar (x,y) = bar y > > instance HasBarMethod ClassB Bool Bool where > bar _ x = x > > test4::Bool = bar ClassB True > test5::Bool = bar ClassC True > test6::Bool = bar ClassD True > >
Sign up for updates to this mailing list. email:
Loading Comments...
Home | News | Patents | Sitemap | FAQ | advertise

Advertising by