Replies: 5 comments
-
| This sounds like an incredibly useful feature! Your first point seems especially relevant to my situation. Probably my biggest issue with the current state of Loyc is that the rules governing  I'm not entirely in agreement with regard to the caching implementation, though. I feel like the primary use case for this feature would be to have a different "view" of an  But why bake (cached) properties of the view into the  Here's what that would look like in practice:     class TypeNode {
      private TypeNode(LNode n) {
        Name = n.Args[0];
        // ...
      }
      public readonly LNode Name;
      // ...
      private static ConditionalWeakTable<LNode, TypeNode> views
        = new ConditionalWeakTable<LNode, TypeNode>();
      public static explicit operator TypeNode(LNode n) {
        TypeNode r;
        if (views.TryGetValue(n, out r)) return r;
        r = new TypeNode(n);
        if (!r.IsValid) throw new ArgumentException();
        views[n] = r;
        return r;
      }
    }One of the key advantages of this design is that it's very much a "pay for what you use" scheme. Views only cost memory when you actually use them. Also, this design interacts nicely with garbage collection: once you're done using a node, the garbage collector will just collect it as well as its views. The code's not incredibly pretty, but it shouldn't be too hard to write a macro for defining new views. IMO, the only real downside to this design is that values in a  This is what a view based on      class TypeNode {
      public LNode Node { get; private set; }
      private TypeNode(LNode n) { Node = n; }
      public LNode Name { get { return Node.Args[0]; } }
      public VList<LNode> BaseTypes { get { return Node.Args[1].Args; } }
      public LNode Body { get { return Node.Args[2]; } }
      public Symbol Kind { get { return Node.Name; } }
      public bool IsValid { get { return EcsValidators.SpaceDefinitionKind(n) != null; } }
      private static WeakCache<LNode, TypeNode> views
        = new WeakCache<LNode, TypeNode>();
      private static TypeNode CreateView(LNode n) {
        return new TypeNode(n);
      }
      public static explicit operator TypeNode(LNode n) {
        var r = views.Get(n, CreateView);
        if (!r.IsValid) throw new ArgumentException();
        return r;
      }
    } | 
Beta Was this translation helpful? Give feedback.
-
| Interesting, I did not know about  The nice thing about your ideas is that they require no changes to  I guess it's a question of how often people want to cache data. So I'd like to look at the memory cost. Let's say I optimize for up to two cached items. If, say, you want to cache one or two things on 25% of nodes... and  How does this compare to an independent  You avoid the cost of a cast, but you gain the cost of a full hashtable lookup (probably with a  I also wonder if there's any valuable feature that would be more than just caching - associating a value permanently with a node, no deletions? Hmm, not sure that that's a good idea. | 
Beta Was this translation helpful? Give feedback.
-
| And let's keep  | 
Beta Was this translation helpful? Give feedback.
-
| Hmmm. I don't fundamentally disagree with your analysis, but isn't it kind of biased in the sense that it takes into account the memory cost of a feature of my suggestion (weak references) that your original idea doesn't have? That's kind of comparing apples to oranges. Surely adding weak references to your solution changes the math? Permanently associating values with nodes would be... invasive. Especially if the values being associated are semantically relevant. That'd essentially add a third type of semantically relevant storage to  | 
Beta Was this translation helpful? Give feedback.
-
| Oh right, I guess I should count only one weak reference (the keys, e.g. using  | 
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
A Loyc tree node (
LNode) typically represents some specific concept, such as a data type name or a class definition. I've been thinking for a long time that we needed some way to conveniently obtain access to convenient "wrapper" around anLNodethat would make it act like some specific type. Now I suspect it's worthwhile to go a step further and provide caching functionality.Here are two specific things that people might want to do:
One: validate a node as being of a specific type and get a wrapper that provides convenient access to it. For example, I could define a structure like this to encapsulate a class definition:
Okay, you can already do this today, and you could use LeMP to generate structures for many node types quickly. However, perhaps in some scenarios you would convert the same Loyc tree to a wrapper many times, requiring validation each time.
Two: compute something from an LNode. We could add caching functionality of some sort to Loyc trees for this. Since nodes are immutable, the idea would be to associate immutable data with the nodes.
My idea is to add some kind of
IDictionary<Identification,object>to each node, with restricted access: the dictionary doesn't exist at first, it is created only when needed, and the values associated with eachIdentificationare computed automatically using some kind of global "registrar" or function table. What isIdentification? I'm uncertain; it might just beSymbol. Anyway, if you have anLNode NthenN[Id]gets theobjectassociated withId. If there is no object associated withId,LNodewill look up the helper functionhassociated withIdin the registrar and callh(N).hreturns a value or object that is returned fromN[Id], and also cached, so that if you callN[Id]again, you get the same object.At any time it should be possible to discard all cached info, even recursively, e.g.
N.ClearCache().So, let's say you're implementing a Java compiler with Loyc trees. You might create a series of
Identificationobjects, one for each kind of node in Java:Node.Package,Node.Expr,Node.ForLoopetc. Then you can callN[Node.ForLoop]to obtain the "while loop" representation of the node.Ahh, but it's an
object- no type information. Can we do something about that? Well, I don't think it's possible to avoid a typecast, but maybe we can make the cast more convenient. First of all, I can't recall at this moment whethernode<ForLoop>[Node.ForLoop]is legal C# syntax, but if so, we can allow that. But it would be better if we could allownode<ForLoop>[], or if that's not legal syntax,node.Get<ForLoop>()(yuck). One way to do this would be to auto-generate anIdentificationobject for each type as it is requested. Then,LNodecould use reflection to find a static functionForLoop.From(LNode)function which would be used to obtain theForLoopobject. However, it would be nice to avoid reflection because sometimes .NET AOT compilation doesn't support it.Then there's the matter of efficiency. Sometimes it is cheap to compute an associated value for a node; other times it is expensive. Sometimes the expense depends on the node (this is an issue for computing hashcodes - hashing an identifier node is trivial, hashing a large class is not.) It would be nice to have some kind of mechanism to avoid caching things that are cheap to compute, particularly if it means avoiding the creation of a relatively expensive dictionary of cached things. So, instead of simply returning a value, the helper function
hcould return two values: one object to be returned and one integer representing how willingLNodeshould be to cache the value (typically proportional to how expensive it was to compute the value or validate that the node syntax was correct). The caching strategy could be user-customizable, within reason... changing strategies should not affect nodes that already exist and have caches.The other element of efficiency is memory usage. A likely optimization is to avoid allocating an entire dictionary when there is only one cached value. In any case, this feature would require adding 1 or 2 words (references) to every
LNode.So @jonathanvdc, does this sound like a useful feature? Is it worth a cost in memory-per-node to support the mere possibility of it?
Beta Was this translation helpful? Give feedback.
All reactions