Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [handly-dev] A milestone build of Handly 0.5

Hi!

I understand better now how this works, thanks for explaining.

Regarding the examples, I believe that the basic example can only use the first strategy, because Xtext creates its own model classes and I think you can't add to their hierarchy. The java example feels a bit heavy, but after some thinking I think that it should be almost enough to reimplement just the model -- the ui can remain mostly the same (possibly use IElement instead of IJavaElement is places). This is just after a quick browsing, so I may be wrong. If there is significantly more work with the Java model than I think, maybe it would work to create a new example, with just a few elements and not much ui, so that the details of the implementations of the different strategies aren't hidden behind irrelevant changes.

Regarding the forked JDT API, if you mean what I think you mean, it would be a cool and useful example too -- it is almost certain that adopters might already have a model and would like to see which parts should be removed and implemented by handly. Actually, maybe that could be even more useful not as a full-grown example, but as a steb-by-step guide, just like "gethandly"? In that case, it would make sense to copy and modify the "gethandly" example instead. BTW, will you update "gethandly" for 0.5 or is it something for later too?

I would have liked to learn the new API while implementing my own model, but unfortunately (as I mentioned before) I am still stuck on Java 6/7 for a while. 

best regards,
Vlad


On Tue, Apr 19, 2016 at 11:20 AM, Vladimir Piskarev <pisv@xxxxx> wrote:
Hi Vlad,
 
Thank you very much for the prompt feedback!
 
Let me try to elaborate on it a bit.
 
* Is any of the three ways to implement a model recommended over the others?
 
Actually, no. A beauty of this new approach (if I may say so) is that there is no good technical reason to recommend one way over the others. Actually, there is not much between them. In each case, the model implementor has complete control over the model API.
 
First, I'd like to emphasize that the provided "extension interfaces" are just mere convenience for "mixing-in" some methods into the model API at the sole discretion of the model implementor. Handly neither requires nor queries these extension interfaces in something like casts, instanceof operators etc. So, if you think that a set of methods defined in an extension interface would be nice to have in your model API, you can extend that interface. If, on the other hand, you don't like some of the predefined methods (say, you'd much prefer to expose methods that return lists rather than arrays), you are completely free to not extend the extension interface that defines those unwanted methods. This decision is made for each of the extension interfaces separately. For example, you could extend, if you like, ISourceFileExtension and ISourceElementExtension, but not IElementExtension.
 
I can, perhaps, think of only one caveat with the extension interfaces: the current version number of Handly, which means the API is not completely finalized yet. In theory, the extension interfaces may still evolve, although I don't anticipate that it will really happen in practice. *But* if you want to be very sure that your model API will not be affected by pre-1.0 evolution of Handly, you might prefer to use the second strategy or even the third one.
 
Speaking of the latter two strategies, it really depends on whether you can tolerate any mentioning of Handly in your model API :-) The most conservative approach would be to start with the third strategy. Its only disadvantage is that occasionally clients of your model API might have a need for a cast to IElement etc. when interacting with some generic Handly-based API (like the Elements and ElementDeltas classes). However, you can always change your mind later on and adopt the second strategy while retaining full backward compatibility for your model API.
 
* What are the use cases where each is better suited?
 
Perhaps the first strategy can make getting started with a new model API a bit easier, especially if you don't care of the finer details of the API very much. However, even the first strategy gives you complete control over the model API, since you are the one who picks and chooses desirable extensions.
 
On the other hand, the third stategy might be a good choice for something like JDT (theoretically speaking), where a dependency on Handly in the model API (even on the marker interfaces) might not be welcome.
 
The second strategy is perhaps a reasonable default if you're really serious about the model API or need to implement a pre-existing API. Please note that this strategy is not necessarily mutually exclusive with the first strategy.
 
* Do I understand correctly that for #2, it means the hierarchy is like below?
 
Not quite: MyElement extends Element which implements IElementImpl. You don't have a need to extend or implement IElementExtension in this case.
 
* Maybe it would be useful to have a small example for each of the ways...
 
Absolutely! My current thinking is to leave the basic example as is (i.e. using the first strategy), and move the Java model example to the second or third strategy, while at the same time making it implement a "forked" JDT API (with somewhat reduced functionality to keep it manageable as an example).
 
However, this goal seems a bit too ambitious for me to undertake in the 0.5 time frame. There is also no time left for significant community contributions to 0.5 (given the necessary Eclipse IP process). So, this looks like a pefect work item for 0.6, and I would certainly welcome contributions and would very much appreciate any help regarding this work, or may be providing a separate smaller example that would demonstrate one of the other strategies (there really is not much between the second and third strategy from the model API point of view). Thanks a lot for suggesting it, Vlad! It would be a really nice contribution. Should we discuss it in more detail?
 
Thanks,
Vladimir
 
 
Hi Vladimir!

I think this looks very nice. I will try to check it out "in action" to get a better feeling. Until then, a couple of questions (I can give partial answers myself, but I'm thinking that a fresh user might not be able to, so these should be part of the introductory reading):

Is any of the three ways to implement a model recommended over the others? 
What are the use cases where each is better suited? 
Maybe it would be useful to have a small example for each of the ways (optimally, I'd say "let's take the Java example and do it the other two ways", but it feels like a bit too much duplication). I can try to provide that as a way for me to get acquainted with the new API.
 
Do I understand correctly that for #2, it means the hierarchy is like below (I hope it gets formatted nicely)?


       +--------------------+          +-----------------------+
       |                    |          |                       |
       |     IMyElement     +---------->     IElement          |
       |                    |          |                       |
       +--------------------+          +-----------------------+
                 ^
                 |
                 |
                 |
       +--------------------+           +----------------------+
       |                    |           |                      |
       |     MyElement      +----------->      IElementImpl    |
       |                    +-----+     |                      |
       +--------------------+     |     +----------------------+
                                  |
                                  |
                                  |     +----------------------+
                                  |     |                      |
                                  +----->    IElementExtension |
                                        |                      |
                                        +----------------------+


best regards,
Vlad


On Mon, Apr 18, 2016 at 2:15 PM, Vladimir Piskarev <pisv@xxxxx> wrote:
Greetings handly-dev,
 
I'm pleased to announce the availability of an important milestone build that early adopters are most welcome to check out and comment on.
 
 
 
Issues addressed in this milestone:
* Java model example: Navigator (https://bugs.eclipse.org/bugs/show_bug.cgi?id=475468)
-- Thanks for contributing this, Ondrej!
* Java model example: Compilation unit editor (https://bugs.eclipse.org/bugs/show_bug.cgi?id=475470)
* Upgrade base target to Luna (https://bugs.eclipse.org/bugs/show_bug.cgi?id=487996)
* Move Handly to Java 8 (https://bugs.eclipse.org/bugs/show_bug.cgi?id=474391)
* Provide EditorUtility (https://bugs.eclipse.org/bugs/show_bug.cgi?id=488547)
* Provide common implementation for navigator LinkHelper and OpenActionProvider (https://bugs.eclipse.org/bugs/show_bug.cgi?id=488548)
* Support XtextEditor clones (https://bugs.eclipse.org/bugs/show_bug.cgi?id=488560)
* Rename some elements of the model API (https://bugs.eclipse.org/bugs/show_bug.cgi?id=491568)
* Move IElement.ToStringStyle to new file (https://bugs.eclipse.org/bugs/show_bug.cgi?id=491647)
* Move ISourceElement.Property to new file (https://bugs.eclipse.org/bugs/show_bug.cgi?id=491649)
* New design for the model API (https://bugs.eclipse.org/bugs/show_bug.cgi?id=491564)
* In general, allow any Object as an Element body (https://bugs.eclipse.org/bugs/show_bug.cgi?id=491570)
* Introduce ElementDelta.Builder API (https://bugs.eclipse.org/bugs/show_bug.cgi?id=491575)
* Make buffers auto-closeable (https://bugs.eclipse.org/bugs/show_bug.cgi?id=476988)
* Make o.e.handly dependency on o.e.core.resources optional (https://bugs.eclipse.org/bugs/show_bug.cgi?id=488819)
 
A few words about the core feature of this milestone: an entirely new design for the model API.
 
After much experimentation and reflection, I gave up on the idea of using mirrors as originally proposed in [1] in favor of what I consider a simpler and more efficient design. There are actually two problems with the mirrors: conceptual and computational weight. In a nutshell, mirrors cost time and memory to create; worse, as acknowledged in the seminal paper [2], when the distinction between base- and meta-level operations is either awkward or ambiguous, the mirrors can just get in the way. Indeed, it is not always obvious in practice whether a method argument or return value should be the element itself or its mirror. To quote from the paper, "In a non-uniform system, each option has drawbacks."
 
So the new design has exactly the same motivation as discussed in the original proposal, but tries to solve the problem without introducing additional concepts or incurring additional performance costs. Let me explain it in brief.
 
In the new design, IElement, ISourceElement, ISourceFile, ISourceConstruct, and IElementDelta are just marker interfaces. Implementors of these interfaces must also implement the corresponding "implementation interfaces" (namely, IElementImpl, ISourceElementImpl, ISourceFileImpl, ISourceConstructImpl, and IElementDeltaImpl), whose method names are all prefixed with 'h' in accordance with naming convention discussed in the original proposal. The provided basic implementation classes Element, SourceElement, SourceFile, SourceConstruct, and ElementDelta thus implement these implementation interfaces and also follow the "h-prefix" naming convention for all their non-static API methods (public or protected).
 
The classes Elements and ElementDeltas provide static methods for generic access to elements and element deltas of a Handly-based model, such as getName(IElement) and getElement(IElementDelta). Usually, those methods just cast their first argument to the corresponding *Impl interface, and call an appropriate method of that interface. As you can see, such simple "reflection facility" doesn't cost much in terms of performance and doesn't introduce entirely new concepts as opposed to the mirror-based approach. The associated "verbosity cost" of calling the static methods instead of the more usual "dot notation" has proven quite manageable so far, although something like Xtend extension methods would certainly be welcome for using this API. I'd like to note, however, that this facility is meant to be used mostly by "generic clients" such as common UI components; "ordinary clients" can use the model-specific API of a concrete model and thus are not exposed to the somewhat increased verbosity in notation.
 
Speaking of the model-specific API, a number of "extension interfaces" (namely, IElementExtension, ISourceElementExtension, ISourceFileExtension, and IElementDeltaExtension) are provided, which model implementors may choose to extend. The extension interfaces provide default methods that delegate to corresponding methods of the classes Elements and ElementDeltas. For example, the interface IElementExtension has a default method getName(), which calls Elements.getName(this). Thus, these extension interfaces can be effectively "mixed-in" to the model at the sole discretion of the model implementor.
 
So, the model implementor still has, basically, the same three choices as outlined in the original proposal:
 
1. The interface for a model element extends IElementExtension (and hence, IElement). This is similar to what has been available since Handly 0.1. An additional advantage vs. the original proposal is that this approach is now quite safe, since new members will not be added to the existing extension interfaces (not even default methods). Instead, new extension interfaces (like IElementExtension2, etc.) will be introduced when/if needed. So, the model implementor always retains control over picking and choosing desirable extensions and, thus, over the whole model API.
 
2. The interface for a model element extends the minimal IElement (only). In the new design, IElement is just a marker interface without any members that could pollute the model API, not even a single method like the hMirror() of the original proposal. Thus, the model implementor is free to form the model API to his liking, or retrofit an existing model interface to extend IElement while retaining backward compatibility.
 
3. The interface for a model element doesn't extend IElement, so it doesn't depend on Handly at all. The drawback is that explicit casts to IElement might occasionally be necessary, although it should not be a big problem in practice.
 
I hope this makes sense. Please feel free to ask questions/leave feedback.
 
Unfortunately, such radical re-design would not be possible without significant breaking changes; I'm really sorry about it. I have yet to describe all API breakages, but I'd like to highlight perhaps one of the more confusing: if you happened to use the methods getElementAt and getSourceElementInfo of the now removed class SourceElements, their corresponding replacements are getSourceElementAt2 and getSourceElementInfo2 in the class Elements, and NOT getSourceElementAt / getSourceElementInfo which are also present in that class. Also, please note that each of the "extension interfaces" needs to be extended separately. For example, ISourceFileExtension extends neither ISourceElementExtension nor IElementExtension. This provides flexibility for the model implementor to pick and choose desirable extensions, but may require some extra care. I'll try to come up with a detailed migration guide a bit later, but in the meantime just let me know if you have any questions or concerns with migration.
 
Thanks,
Vladimir
 

_______________________________________________
handly-dev mailing list
handly-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/handly-dev


_______________________________________________
handly-dev mailing list
handly-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/handly-dev


Back to the top