I'm still having a bit of trouble with inherit. The problem was that: open class List { .. } open [T with Str[T]] Str[list[T]]; open [T with Eq[T]] Set[list[T],T];
should work as: open class List { ... inherit [T with Str[T]] Str[list[T]]; inherit [T with Eq[T]] Set[list[T],T]; } The difference is that the second form makes str and \in of list a member of the class which then gets opened, the first form opens these functions separately. The problem in general with this opening is that it is subject to hijacking: any function of the same name defined by the user in global space will hide the opened version, and that will change the semantics of the library. The way around this is to make library classes open what they required inside themselves, for example: class List { .. open String; ... } ensures that all the List functions that need strings get the ones from String, rather than the global space. The client programmer can't pollute String. Ideally, the way to do this with typeclass instances is inherit them inside the class, as shown. That means that when a library class opens List, it gets the functions from Set, including \in for example. With the first form, it gets them from the global space, which can be hijacked. The std library is protected from hijacking by a quirk of the compilation model: the pre-compiled headers are built first, before there's any user code, so its actually a "bug" that a user hijacking function doesn't actually hijack the library code :) The old problem with inherit here was that inherit[U] X[U * int * &U] // for example just didn't work. I fixed that and got a infinite recursion. This comes about because the type arguments of X here, namely U * int * &U have to be evaluated in some scope, possibly including the class containing the inherit clause. The problem is .. the members of X are IN that class! The solution is just to exclude that class from the lookup. That stops the recursion. Unfortunately .. it also stops the class working for unknown reason: class List { type list = ... .. inherit[U] Set[list[U],U]]; ...} should fail because if we exclude List from the binding of the argument of Set, we will not find the symbol "list". Indeed, I end up with a lookup failure: Client Error binding expression not((\in (suffix, (list ("flx", "flxh"))))) CLIENT ERROR [lookup_name_with_sig] Can't find \in of string * list[string] In /Users/johnskaller/felix/build/release/tools/webserver.flx: line 589, cols 6 to 35 but I don't really understand why. The error indicates Set[list[U],U] wasn't actually inherited. This should cause a failure inheriting it .. not just leave the functions out! It works fine with the open model! This thing is very hard. We probably want to make inherit work *including* the current class but not any stuff injected into it with inherit (since that would lead to a recursion). Or at least that particular inherit. Ideally we'd give it a try and drop things that caused a recursion: backup and try again until we've stripped just enough environment to do the binding. But we have a control inversion problem: the choices are made inside functions, and there's no easy way to back out of a deeply nested recursion other than throwing an exception, and doing that is very VERY hard because then we have to figure not only where to catch it, but what information to put into it to make a retry that will exclude the cause of the recursion. In most cases self-recursions in lookup are evil and indicate an error. But there are some cases where this isn't so, particularly when binding recursion types, since Felix can handle a fix point in types. Well, some of them anyhow! Using fixpoints is the way to handle the other lookup issues too, but its very hard. Lookup failures aren't single point failures, because scopes contain *sets* of things. Note: this problem is more or less unique to Felix's ultra-advanced lookup model. Languages with simpler lookup models, such as Ocaml, will never have this problem. C++ doesn't have this problem because the only place setwise lookup is done is in binding the interfaces of class member functions. It uses a special rule to stop silliness with types called the reconsideration rule. This rule basically disallows forward references to types in a C++ class, but stiil allows member functions to be bound collectively after the rest of the class is seen. Such a lookup would be plagued by remembering where the member was defined to retain an outer type name otherwise. Anyhow, just to reinterate the issue I'm grappling with: (nice Nautical term that, grappling .. grabbing onto an enemy ship for the purpose of boarding her ..) In class A we need to inherit from some class B with B's type arguments bound to terms from A. The problem is that the complete scope of A then contains the entries from B specialised by the arguments, and to calculate entries in A then depends on binding these arguments in the context of A .. which we're in the middle of trying to calculate! class List { type list = ... inherit Set[list]; } to get Set's functions into List, we have to lookup "list" in List, but the scope of List includes those things from Set .. infinite regress. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ This SF email is sponsosred by: Try Windows Azure free for 90 days Click Here http://p.sf.net/sfu/sfd2d-msazure _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language