Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    #16
    This question was covered in the thread above, of course, the thread is very long and full of incorrect approaches, so it's easy to miss:

    If you want to encapsulate that, you can make a subclass of DynamicForm that is aware of your special CanvasItem that isn't capable of change notifications, and retrieves its value right before save and validation. Or, encapsulate it at a higher level, such as a combined grid and form component like that shown in the Pattern Reuse sample.
    In other words, say you have a form you want to populate with a Record from a ListGrid. Make your own variant of editRecord() that calls the original editRecord() but also populates the CanvasItem via setValue(). Use the same pattern when saving. Re-use this by using your own custom subclass of DynamicForm pervasively, which is a standard approach for extending the databinding system.

    We plan to add APIs to CanvasItem to make it possible to just plug into an ordinary DynamicForm without using a subclass (already possible in SmartClient), as well as create samples for this. However this will not be based on overriding setValue(), because there are ~10 type-specific variants of that method.

    We will not be using the "final" qualifier because in most Java libraries this is used to indicate that a method is *designed* to never be overridden. In SmartGWT it's just not yet a valid override point and may be in the future.

    Comment


      #17
      Regarding the final issue, even if not using the word final it would be great to know if it is a valid override point - some javadoc could do that. It's really pretty frustrating to keep trying different points until you find one that works.

      I'm still hoping that a user wiki appears soon that we can reference. As you point out, the forums are full of bad examples. It really makes learning really hard if your case is not covered in the showcase.

      Comment


        #18
        If a method is both designed as a override point and set up as an override point in SmartGWT, the JavaDoc already says "this is an override point".

        We don't plan to mark anything that has not been designed as an override point, even if it's possible to override it. As is sometimes said, "inheritance breaks encapsulation" - if you override a method that where the developer has not thought through the consequences of an override and documented certain assumptions you can make in this case, there's a high chance your override may function differently in the future.

        Comment


          #19
          sounds reasonable.

          Comment


            #20
            Originally posted by Isomorphic
            We will not be using the "final" qualifier because in most Java libraries this is used to indicate that a method is *designed* to never be overridden. In SmartGWT it's just not yet a valid override point and may be in the future.
            You could also make the argument that most Java libraries don't have this particular pattern of overriding a method that, under the covers, doesn't "exist" yet. :)

            If you already have to explain to your users that "this library is different in that you should look at the javadoc for 'override point' keywords", you might as well instead explain that "we use 'final' to denote both APIs never designed to not be overridden, as well as APIs not ready to be overridden". You then gain programmatic enforcement of the state of the underlying library. Just think of the use case where one changes versions of the SmartClient library. Someone would have a fun time auditing every method call's javadoc to see what override points changed? Instead, their IDE or compiler would immediately tell them what methods are attempting to override methods marked final. In the latter case, you instantly know your implementing code's compatibility with a particular version of SmartClient. (Although it's probably a less likely use case where a method goes from not being final to final from an earlier version of smartclient to a later version.) On your end, you could even write a Java tool that uses reflection to give you a "diff" of methods gone from final to not final, thus providing a snapshot of what methods are now "ready" as override points, between SmartClient versions.

            Just my 2 cents.

            Cheers,

            Alex
            Last edited by twelve17; 4 May 2011, 06:53.

            Comment


              #21
              Yes - programmatic enforcement with all that that implies, including headaches compiling against different versions, where you have to change code that's only intended to run in a newer version just to compile against the old version..

              It would also prevent you from creating a valid override point via JSNI, which is straightforward once you're familiar with the process.

              Aside from all this, and aside from it conveying the wrong idea, it also simply would not work. There are APIs you are not intended to override from user code, but which are overridden by the framework.

              So no, definitely not either desirable or feasible.

              Comment


                #22
                Originally posted by Isomorphic
                Yes - programmatic enforcement with all that that implies, including headaches compiling against different versions, where you have to change code that's only intended to run in a newer version just to compile against the old version.
                Isn't that the point? Why would I want my code to compile properly against an old version, and me left clueless as to whether it's actually going to *function* as expected? What about those methods no longer being called? Wouldn't you want to know they are no longer valid?

                If SmartGWT, as a framework, didn't have the 'luxury' of being loosely coupled to an underlying JS library, you would *have* to deal with the 'headaches'. If I downgraded my server side code to an older version of, say, Spring libraries, I would be forced to change any APIs that did not exist then. You are essentially saying, "I will ignore those changes at the compiler level because I can."

                Originally posted by Isomorphic
                It would also prevent you from creating a valid override point via JSNI, which is straightforward once you're familiar with the process.
                Maybe I am not understanding this particular process correctly. I can revisit this to see if maybe I'm approaching customization the wrong way.

                Originally posted by Isomorphic
                Aside from all this, and aside from it conveying the wrong idea, it also simply would not work. There are APIs you are not intended to override from user code, but which are overridden by the framework.
                There are patterns in native Java frameworks that have methods only intended to be used by the framework and not by implementors. I don't recall any of them involving relying on javadoc to determine whether your method override would actually do something or not. Using 'final' may not be conveying the 100% "right" message, but I am not sure that the current solution conveys the "right" message either.
                Last edited by twelve17; 4 May 2011, 07:16.

                Comment


                  #23
                  Frequently, you want your code to compile against an old version even though you are using features of a new version when that version is available. If you don't understand this from just this brief explanation, you may just need more or larger projects under your belt - this has to do with how you manage common source across multiple versions of an application that needs to run in different environments.

                  All normal customization is done through normal Java overrides. You should not change your basic customization approach based on the awareness that JSNI *could* be used to create an override point where an override point was not designed-in. This would be rarely used by advanced developers, but is still an important capability to maintain.

                  So again, not desirable for these reasons, and even without these serious drawbacks, conveys the wrong message. Concretely, we would receive a steady stream of questions about why APIs are final, no matter how prominently this was explained in the FAQ or QuickStart or website.

                  Also, not feasible without, at the least, restructuring in a bizarre way (because remember, all these methods are actually overridable in SmartClient).

                  If you're interested in contributing to the framework, there's samples you could create, docs to enhance, etc - with 3+ independent reasons why this suggestion will not be implemented, each sufficient on it's own, there's no point in further discussion.

                  Comment


                    #24
                    Originally posted by Isomorphic
                    Frequently, you want your code to compile against an old version even though you are using features of a new version when that version is available. If you don't understand this from just this brief explanation, you may just need more or larger projects under your belt - this has to do with how you manage common source across multiple versions of an application that needs to run in different environments.
                    I do understand the concept, and I retain my point that the reason this pattern even exists is due to the nature of the loose SmartGWT/SmartClient coupling. If the library was 100% Java, this pattern would not be possible, and a different pattern would be employed (maybe a custom annotation/AOP combo that would give you compile time compliance for your older-version testing, plus a run-time way to determine insertion points--anything that is more programmatic than javadoc would help).
                    Last edited by twelve17; 4 May 2011, 07:47.

                    Comment


                      #25
                      Actually, one of the purposes of libraries like Spring is to bring similar loose coupling to all-Java systems.

                      In general, compile-time checking in Java, while great for simpler code, can be an albatross in more advanced scenarios where compile-time checking or even run-time checks produce fictitious incompatibilities (such as code being considered incompatible because a method has moved to a superclass). It is one of the less understood benefits of Spring that it reduces fictitious incompatibilities like these through pervasive use of reflection.

                      Comment


                        #26
                        Originally posted by Isomorphic
                        Actually, one of the purposes of libraries like Spring is to bring similar loose coupling to all-Java systems.

                        In general, compile-time checking in Java, while great for simpler code, can be an albatross in more advanced scenarios
                        Hence my mention of the alternative approach of using java annotations instead of javadoc to provide run-time checking of methods overriding those that are not insertion-point ready. It would allow for compilation to succeed yet at least produce some warnings somewhere that some code is not "compatible".
                        Last edited by twelve17; 4 May 2011, 07:57.

                        Comment


                          #27
                          If you were to propose a concrete implementation of this that would give warnings similar to deprecation but not produce a compilation error, it would be easy for us to pervasively apply.

                          Comment


                            #28
                            Originally posted by Isomorphic
                            If you were to propose a concrete implementation of this that would give warnings similar to deprecation but not produce a compilation error, it would be easy for us to pervasively apply.
                            I could look into this. If you can tell me a little about how you guys handle management of these type of methods on your end, maybe it could be implemented in a way that allows it to help framework developers mark such methods in addition to implementors be notified of incompatibilities.

                            I wonder if there could even be a run-time implementation and setting that causes startup to fail if any incompatible code is found.

                            Comment


                              #29
                              If you look at any source file you'll see that many methods are just passed through like this:

                              Code:
                                      /**
                                       * Re-evaluates {@link com.smartgwt.client.widgets.grid.ListGridField#showIf} for each field, dynamically showing and &#010 hiding the appropriate set of fields&#010
                                       */
                                      public native void refreshFields() /*-{
                                          var self = this.@com.smartgwt.client.widgets.BaseWidget::getOrCreateJsObj()();
                                          self.refreshFields();
                                      }-*/;
                              What we would need is an annotation that would cause a warning, but not an error (compile time or runtime) if a developer attempts to override this method in a subclass.

                              Comment


                                #30
                                I've just checked out the smartgwt sources and will start looking at the layout.

                                There are two ways to approach "marking" smartgwt classes: those that can be allowed to be overriden (i.e. something like @OverridePoint) or those that should not (something like @Final, or @NonOverridePoint). I am not sure what would make sense at this point: are there more "java-override-able" methods that are smartgwt override points vs not? What would make more sense from a framwork maintenance point of view?

                                For now, let's assume that methods that have @OverridePoint are allowed to be overriden by implementors, and those that lack the annoation are not allowed.

                                Thinking outloud, maybe the solution could involve:

                                1. a annotation preprocessor which takes a property: a package of sources which contain the set of classes in the smargwt framework. I suppose it could default to "com.smartgwt.client".

                                2. An annotation class defining @OverridePoint

                                I haven't toyed around with preprocessors enough to know for sure, but I will see if it's possible to have the preprocessor scan the classpath for classes not in the package specified in #1, which extend classes in said package, which then override methods.

                                The downsides to this approach are:

                                - you must pass on the -processor parameter to the java compiler to enable this
                                - not sure how fast the preprocessor would be / how much it would slow down compiling, which may be annoying. (that being said, maybe folks can just not run it all the time)
                                - if an implementor creates their own class using the same package path as the framework's, the preprocessor would assume that those should be checked as well. perhaps the convention would be that if you must create classes in that package for some reason, that you too use the @OverridePoint annotation consistently with the framework usage

                                Thoughts?
                                Last edited by twelve17; 5 May 2011, 07:05.

                                Comment

                                Working...
                                X