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

Reply via email to