Re: correctness, generics, and spaces
James Grahn wrote: What is the bigger picture you're concerned with? Reliability, developers experiencing unexpected run time errors and compatibility issues in deployed code when using Generics in Service API. In our earlier discussions I provided an example of how generics can remain inside compile time boundaries while interacting with a service. I have an experimental section that can be found on svn. http://svn.apache.org/viewvc/river/jtsk/skunk/pepe/src/org/apache/river/api/lookup/ I've used a wrapper class that performs type checks, so the client can use generics safely, this gets rid of most of the boilerplate code without the compromise in type safety. If you use a wrapper class with your new javaspace interface using generics, you can use the existing Javaspace API, and perform type checks in the wrapper class, this will eliminate the boilerplate code. Since this sort of wrapper class could be reused by a number of clients, it might make sense to use annotations, or a wrapper service as Gregg mentioned. When the wrapper class receives the return object, it checks it's class is the same type as the parameter before returning it to the client, if incorrect it can throw a RemoteException that will be handled by the client rather than a runtime exception which will cause the client jvm to exit. But because it can be difficult to test for generic types in java syntax, it would appear more logical to weave the check in byte code when the Generic type has been replace by a specific known cast. So we throw a RemoteException prior to the cast, rather than a Runtime exception. Alternatively we can just catch a ClassCastException and treat it the same as a RemoteException. Doing so would allow people to develop using Generics in their service API, without degrading reliability. This doesn't take into account any incompatibilities that Generics would introduce to services, just type safety and reliability. Obviously during lookup, we'd want to ensure we've selected the implementation of the service we want. EG: interface DeliveryService { deliver(); } Due to erasure T will be replaced by Object, in all cases, now we might have a service that delivers Apples, another might deliver Sausages, you don't want a Sausage if your expecting an Apple. In this case you'd want an Entry in the lookup service that defines the expected return value. However a service Entry might be misconfigured (the risk arises whenever data is duplicated) and return a Papaya instead of a Sausage. If the client bytecode performs a type check, the client will be able to catch an exception So it's worth asking a question, should we promote the use of Generics in Service API? We could require they must explicitly declare a ClassCastException as well as a RemoteException or IOException and leave the onus on the client to catch the ClassCastException? So far there have been the following proposed approaches for handling Generics over Remote connections: 1. With force of sufficient reasoning for each application, attempt to avoid incorrect type casts. 2. Provide a wrapper class for a service (Gregg's also made a similar suggestion), to perform type conversions over compile time boundaries. 3. Provide a tool to weave class cast checks that throw a subclass of RemoteException. 4. Require a Service that contains Generics to declare it throws ClassCastException, even though this is a runtime exception. 4 is ok for the return values, but what about Generic parameters? On the service side, the server would need to catch a ClassCastException and return a RemoteException to the client if it needs anything other than Object. The Service would need an Entry describing Generic parameter types it accepts? The Service and it's smart proxy were compiled together, so they are type compatible, however the client and smart proxy were compiled separately, this is exactly where ClassCastExceptions will occur with compiler generated type casts when the proxy and client interact. A ClassCastException will cause a runtime exception in the client JVM, it will exit. It could potentially be used for DOS attacks. The Service API contract between the client and proxy will have a degree of uncertainty when using Generics, it's a vague contract that's missing a vital piece of information due to erasure. This degree of uncertainty doesn't exist in an interface lacking Generics. Note the Service API doesn't need to extend Remote, it can be a local interface. This is an interesting exercise, but I do wonder what exactly it is we gain by using Generics in Service API? It's worth noting that Generics are not supported in arrays either, developers readily accept that design decision, not all developers appear ready to accept the limitations Generics present with separately compiled code. This is a limitation of the Java language rather than a
RE: correctness, generics, and spaces
This makes total sense to me. Shay -Original Message- From: Dan Creswell [mailto:dan.cresw...@gmail.com] Sent: Thursday, June 02, 2011 11:58 AM To: dev@river.apache.org Subject: Re: correctness, generics, and spaces On 2 June 2011 14:11, James Grahn wrote: > On Thu, Jun 2, 2011 at 3:06 AM, Peter Firmstone wrote: >> Are you suggesting type safety is NOT a necessary language feature in >> distributed code? > > Not at all. > > However, type safety is not a feature which is the exclusive terrain > of the compiler. With the force of sufficient reasoning, type safe > code can be written without the compiler's explicit blessing. > I recall one of the reasons for introducing generics was because force of sufficient reasoning proved ineffective such that people would get runtime casting problems when extracting objects from collections. Regardless we can have an endless debate about this or do some practical experimentation. So Why don't you branch Outrigger, spec a new JavaSpace interface (e.g. JavaSpace2011) and then release it as an experiment to the community at large? That way you can: (1) See what uptake/appetite is like (2) Gain valuable feedback (3) See if the community finds dark corners and has views on what they want done about them (if anything) That will make for a much more informed debate IMHO (and I'm not saying the debate we're having at the moment isn't useful but some of us have more experience than others and conflicting views which makes progress hard. A good way to solve that is put something out into the real-world and see what happens).
Re: correctness, generics, and spaces
On Thu, Jun 2, 2011 at 11:58 AM, Dan Creswell wrote: > I recall one of the reasons for introducing generics was because force > of sufficient reasoning proved ineffective such that people would get > runtime casting problems when extracting objects from collections. I find the comparison apt: the choice is making a correct cast in a central location vs. having everyone manually cast. > Regardless we can have an endless debate about this or do some > practical experimentation. So We do have a platform for practical experimentation already. The generics branch of the code has the bulk of what's under discussion, though it needs a small patch to eliminate a corner case (again, coming soon). That branch, however, mutates the existing interfaces and classes. If we wish to present both interfaces as options to users, that will have to be changed. Which is entirely doable, if that's the consensus for a next step. jamesG
Re: correctness, generics, and spaces
On 6/1/2011 11:38 PM, James Grahn wrote: On Wed, Jun 1, 2011 at 11:33 PM, Peter Firmstone wrote: Remember the compiler doesn't type check dynamic code conversion, only static conversion. Dynamic happens at runtime. Services are dynamic, discovered at runtime. As I said, I believe that with one additional proviso (which can be enforced at runtime), all dynamic casts will be correct. To recap, that proviso is abolishing unassigned type variables from Entry classes. Could be mistaken. Would be interested in a counter-example. The proposal is to use method-level generics, as follows: T read (T template) Have you tried crafting a wrapper, proxy class which advertises the generified interface, and does the casts in one place, instead of doing it everywhere? I'm just wondering if we could just provide such a class, for now, and see how that works for people so that all of the "problems" would be in the client, in real code, where they could be "fixed" or "understood", before committing to a new API. It would require new interface definitions that encompassed the current tree from Javaspace05 I believe. Then, we could, for example, create a proxy preparer implementation that wrapped to the generic interface as one way to use the existing mechanical steps that should be in use, to result in a new interface that is generified. Thoughts? Gregg Wonderly
Re: correctness, generics, and spaces
On 2 June 2011 14:11, James Grahn wrote: > On Thu, Jun 2, 2011 at 3:06 AM, Peter Firmstone wrote: >> Are you suggesting type safety is NOT a necessary language feature in >> distributed code? > > Not at all. > > However, type safety is not a feature which is the exclusive terrain > of the compiler. With the force of sufficient reasoning, type safe > code can be written without the compiler's explicit blessing. > I recall one of the reasons for introducing generics was because force of sufficient reasoning proved ineffective such that people would get runtime casting problems when extracting objects from collections. Regardless we can have an endless debate about this or do some practical experimentation. So Why don't you branch Outrigger, spec a new JavaSpace interface (e.g. JavaSpace2011) and then release it as an experiment to the community at large? That way you can: (1) See what uptake/appetite is like (2) Gain valuable feedback (3) See if the community finds dark corners and has views on what they want done about them (if anything) That will make for a much more informed debate IMHO (and I'm not saying the debate we're having at the moment isn't useful but some of us have more experience than others and conflicting views which makes progress hard. A good way to solve that is put something out into the real-world and see what happens).
Re: correctness, generics, and spaces
On 6/2/2011 6:11 AM, James Grahn wrote: On Thu, Jun 2, 2011 at 3:06 AM, Peter Firmstone wrote: Are you suggesting type safety is NOT a necessary language feature in distributed code? Not at all. One of the big questions in O-O language design is the extent and timing of type checking. At one extreme, we have Java that does many checks at compile time. At the other extreme, some languages take the view that if an object has a method that method can be called, regardless of any types. However, type safety is not a feature which is the exclusive terrain of the compiler. With the force of sufficient reasoning, type safe code can be written without the compiler's explicit blessing. Personally, I find it easier to produce solid code in languages that do compile time type checking to the extent that is possible, remembering Rice's theorem. I like Java. However, there are situations in which checking can only be done at run time, and some of those situations will arise in River. Patricia
Re: correctness, generics, and spaces
On Thu, Jun 2, 2011 at 3:06 AM, Peter Firmstone wrote: > Are you suggesting type safety is NOT a necessary language feature in > distributed code? Not at all. However, type safety is not a feature which is the exclusive terrain of the compiler. With the force of sufficient reasoning, type safe code can be written without the compiler's explicit blessing. So my question is more along the lines of: why do you not consider these operations type safe? Are there any examples which violate the typing? > How do we tell developers when they develop their services using Generics, > the static compile time safety guarantee of generics doesn't exist in > dynamically loaded code? They will of course expect type safety so this may > come as a shock to some, how will this reflect on River? How does it reflect on River that read and take will not return the type of the template for concerns of type safety, when the documentation says that they will? Is the documentation wrong? Is the fundamental approach wrong? How does it reflect on River that every use of a space requires a cast, making it feel increasingly antiquated in the post-1.5 world? > I don't wish to sound discouraging, but I think ignoring the bigger picture > is not the solution for River, I acknowledge that in your particular case > you have figured out work arounds with some corner cases to be avoided, but > the compromises made may not be acceptable for other service > implementations. What is the bigger picture you're concerned with? You don't believe that the JavaSpace API should be made generic (even if correct) until every River API is genericized? Or that the additional proviso on Entry classes will be unacceptable to the other APIs that use Entries? (I'll try to look for an example of this in the other uses of Entry, but given that the design predates Java 1.5, I don't expect to find any problems excluding a feature introduced in 1.5.) Type-safety is something that can be empirically disproven. An example wherein type safety is broken (especially if it's worse than before) will do just that. If, on the other hand, we're moving on to policy positions concerning the timing of updates to River APIs, let's have that discussion instead. > Peter. james
Re: correctness, generics, and spaces
I have to agree with Peter on this. It's easy to make a "good enough" solution using generic, particularly if you're developing services within a single safe environment. E.g. At your company where all services are written by people on your team and hosted on a private company subnet. But River is bigger than that and needs to be able to cater for all usages, such as those which aren't as cozy as the one above. I'm particularly guilty of forgetting that since my usage if River/Jini is limited to the above. In my opinion, one of the things River needs to avoid is making changes that *imply* safety even if provisos are placed in documentation somewhere. since (correct use of) generic imply safety, we need to make sure our implementation of them provides that safety, in all cases. Like Peter, I don't want to sound discouraging, but we need to make sure any implementation is the correct one, long term. I look forward to reviewing your patch though! Cheers. On 2 Jun 2011 08:15, "Peter Firmstone" wrote: > James Grahn wrote: >> but I'd >> appreciate some clarification as to what that objection is. I don't >> believe that any annotations or fancier tools will be necessary. >> > > Are you suggesting type safety is NOT a necessary language feature in > distributed code? > > By adding a Generic JavaSpace API to River it suggests that Generics > work as expected in Services and uphold type safety rules. > > But is dropping type safety to eliminate some boilerplate code is an > acceptable compromise? > > How do we tell developers when they develop their services using > Generics, the static compile time safety guarantee of generics doesn't > exist in dynamically loaded code? They will of course expect type safety > so this may come as a shock to some, how will this reflect on River? > > The problem is that if we move forward now and support generics without > type safety, it's going to be much harder to fix later. > > I think we need to investigate solutions implementing type safety with > Generics in dynamic code. Then you can forget about your corner cases, > they are symptoms of unsafe type conversions that will vanish with the > right solution. > > I'm not saying don't use generics, please experiment, but they're not > stable until type safety issues have been properly addressed. Until we > address Generic type safety in dynamic code which Services are, we > should say it's experimental. > > I don't wish to sound discouraging, but I think ignoring the bigger > picture is not the solution for River, I acknowledge that in your > particular case you have figured out work arounds with some corner cases > to be avoided, but the compromises made may not be acceptable for other > service implementations. > > I'm interested in OpenSpaces type safety, namely: > > *Generics Support* – developers can use generics to avoid unnecessary > casting and make their interaction with the space more type-safe. > > How did they make OpenSpaces more type-safe using Generics? > > Peter. > >
Re: correctness, generics, and spaces
James Grahn wrote: but I'd appreciate some clarification as to what that objection is. I don't believe that any annotations or fancier tools will be necessary. Are you suggesting type safety is NOT a necessary language feature in distributed code? By adding a Generic JavaSpace API to River it suggests that Generics work as expected in Services and uphold type safety rules. But is dropping type safety to eliminate some boilerplate code is an acceptable compromise? How do we tell developers when they develop their services using Generics, the static compile time safety guarantee of generics doesn't exist in dynamically loaded code? They will of course expect type safety so this may come as a shock to some, how will this reflect on River? The problem is that if we move forward now and support generics without type safety, it's going to be much harder to fix later. I think we need to investigate solutions implementing type safety with Generics in dynamic code. Then you can forget about your corner cases, they are symptoms of unsafe type conversions that will vanish with the right solution. I'm not saying don't use generics, please experiment, but they're not stable until type safety issues have been properly addressed. Until we address Generic type safety in dynamic code which Services are, we should say it's experimental. I don't wish to sound discouraging, but I think ignoring the bigger picture is not the solution for River, I acknowledge that in your particular case you have figured out work arounds with some corner cases to be avoided, but the compromises made may not be acceptable for other service implementations. I'm interested in OpenSpaces type safety, namely: *Generics Support* – developers can use generics to avoid unnecessary casting and make their interaction with the space more type-safe. How did they make OpenSpaces more type-safe using Generics? Peter.
RE: correctness, generics, and spaces
GigaSpaces XAP application server includes the OpenSpaces library that is mainly the client side implementation and the backend side that includes the JavaSpace implementation and many other server side components. OpenSpaces is provided under the Apache License, Version 2.0. The GigaSpaces distribution contains the source code of the OpenSpaces package under the \gigaspaces-xap\lib\optional\openspaces folder. The underlying GigaSpaces XAP server side implementation is provided in its binary distribution format. See more here: http://www.gigaspaces.com/wiki/display/XAP8/OpenSpaces+FAQ#OpenSpacesFAQ-WhatistheopensourcelicenseforOpenSpaces%3F http://www.gigaspaces.com/wiki/display/XAP8/OpenSpaces+FAQ#OpenSpacesFAQ-HowisOpenSpacesrelatedtoJavaSpaces%3F The free edition is actually not that limited. See details about the LiteEdition here: http://www.gigaspaces.com/LatestProductVersion Shay -Original Message- From: Patricia Shanahan [mailto:p...@acm.org] Sent: Wednesday, June 01, 2011 6:33 PM To: dev@river.apache.org Subject: Re: correctness, generics, and spaces On 6/1/2011 10:31 AM, James Grahn wrote: ... > I am now wondering: is the Gigaspaces code available? Under what > license? And is anyone there interested in contributing? ... My understanding is that GigaSpaces is a commercial product, although a limited version is available for free use. See http://www.gigaspaces.com/licensing. For that reason, I am trying to avoid importing into River any code or even ideas from Gigaspaces. Of course, Apache-compatible licensing would change all that. Patricia
Re: correctness, generics, and spaces
On Wed, Jun 1, 2011 at 11:33 PM, Peter Firmstone wrote: > Remember the compiler doesn't type check dynamic code conversion, only > static conversion. Dynamic happens at runtime. Services are dynamic, > discovered at runtime. As I said, I believe that with one additional proviso (which can be enforced at runtime), all dynamic casts will be correct. To recap, that proviso is abolishing unassigned type variables from Entry classes. Could be mistaken. Would be interested in a counter-example. The proposal is to use method-level generics, as follows: T read (T template) The primary effect of this change is upholding the stated contract of read/take, while reducing boilerplate. When we had our first discussion of generics, a corner case was pointed out that was problematic with or without generics. Some felt it was worse with generics. The corner case can be removed, as I outlined. If the casts are always correct (counter-example welcome), there might still be something objectionable about this change... but I'd appreciate some clarification as to what that objection is. I don't believe that any annotations or fancier tools will be necessary. I hope to submit a patch for the generics branch in the next few days, unless the discussion proves the idea untenable. > Peter. james
Re: correctness, generics, and spaces
I believe an annotation that flags ASM to post process the byte code to add runtime type safety checks would do the trick.| Then we can say, yes Generics are supported in remote code, you just need to add this @RuntimeServiceCheck annotation. Perhaps one of the following annotions: @RuntimeCheckedConversion @DynamicCheckedConversion Remember the compiler doesn't type check dynamic code conversion, only static conversion. Dynamic happens at runtime. Services are dynamic, discovered at runtime. Peter.
Re: correctness, generics, and spaces
Patricia Shanahan wrote: On 6/1/2011 6:19 PM, Peter Firmstone wrote: The argument for generics in remote interfaces is to reduce boilerplate code, the argument against is, it introduces unchecked type casts. (See earlier discussion) Is there another way to reduce the boilerplate code, using annotations perhaps? ... Could we use annotations to get rid of the "unchecked conversion" warnings? As I understand it, the compiler generates code that is type safe even if e.g. a collection contains references to objects of unexpected classes. | Normally in code compiled and linked at compile time, @SuppressWarnings("unchecked") would do the trick, since the compiler catches the error. ||However in code compiled separately no warning will be issued when linked at runtime, the compiler is not involved. Services and clients come together dynamically at runtime, so they miss out on compiler type checking. No compiler errors will be issued, some code just works, other code doesn't and fails with a runtime exception. EG, A Service interface method: T get(); A service is compiled and type checked in bytecode to use: Apple get(); The client is compiled and type checked in bytecode to use: Orange get(); The client and service use the same service interface, but they are not compatible. They might be compatible as Fruit and have the same method eat(), but they will fail at runtime as each is cast to it's own type. Typically if only one developer knows about the service and clients, there are no issues, the unchecked type casts, never get cast to the wrong type. Involve a group of developers working together on a project, then things will start to fail. I believe an annotation that flags ASM to post process the byte code to add runtime type safety checks would do the trick.| Then we can say, yes Generics are supported in remote code, you just need to add this @RuntimeServiceCheck annotation. I can see the attraction to adding Generics to Javaspace, it looks like a collection after all. But typically a Generic collection instance is a collection of a single common type, not many different types. The other problem is the type being returned might not exist at the client, so it is loaded by the proxy ClassLoader, its type is not visible to the client, it needs to be cast to a common supertype, normally defined in the service interface, this problem is unfortunately more complex that it first appears. So I'm hoping that some day we can come up with a simple tool so developers don't have to understand the details, if it isn't compatible, you catch a RemoteException and move on. Peter.
Re: correctness, generics, and spaces
On 6/1/2011 6:19 PM, Peter Firmstone wrote: The argument for generics in remote interfaces is to reduce boilerplate code, the argument against is, it introduces unchecked type casts. (See earlier discussion) Is there another way to reduce the boilerplate code, using annotations perhaps? ... Could we use annotations to get rid of the "unchecked conversion" warnings? As I understand it, the compiler generates code that is type safe even if e.g. a collection contains references to objects of unexpected classes. Patricia
Re: correctness, generics, and spaces
The argument for generics in remote interfaces is to reduce boilerplate code, the argument against is, it introduces unchecked type casts. (See earlier discussion) Is there another way to reduce the boilerplate code, using annotations perhaps? Or perhaps generics in combination with an annotation, then we can use ASM to weave in type cast checks. A developer writing code, might not know what type of object T is, but after compilation, it will be declared as a specific type in bytecode. The weaved bytecode can simply throw an exception that extends RemoteException, perhaps called RemoteTypeCastException. This way the client is protected from a malicious service, designed to create runtime exceptions using class cast exceptions. Unfortunately I don't have the time right now to write such a tool, but it would make the use of Generics in remote interfaces typesafe. I'm willing to help where possible if someone has the desire to take up the cause and get it started. At some stage we will probably support Generics, at this point it's just easier to tell users that Generics are still experimental. Perhaps annotations and ASM could be used to simply proxy verification boilerplate code too. Cheers, Peter. James Grahn wrote: On Tue, May 31, 2011 at 10:51 PM, Shay Hassidim wrote: James, In case this helps - After similar debates over the years we at GigaSpaces end up with: T read(T template) T take(T template) write(T entry) Quite interesting. This is exists presently in the experimental generics branch, except the type is . I take this to mean you did not address the corner case that worried many on this list? Does it simply prove to not be an issue in your experience? See more here: http://www.gigaspaces.com/docs/JavaDoc8.0/org/openspaces/core/GigaSpace.html Please note we support POJO as well with our implementation as space classes and not just Classes implementing the Entry interface. This works very well for us. Entry, of course, is just a marker interface. When you say "POJO", though you mean Java objects without any requirements upon them? (e.g. no requirement of a public, no-arg constructor, no need for public fields, etc.) The inclusion of asynchronous calls using Futures is also quite noteworthy, as is your treatment of "snapshot". I was about to start poking the mailing list about snapshot myself, albeit with a different proposal than yours. I am now wondering: is the Gigaspaces code available? Under what license? And is anyone there interested in contributing? Shay Hassidim Deputy CTO By the way, welcome! If nothing else, your feedback in discussions will prove valuable, I'm sure. james -Original Message- From: James Grahn [mailto:grahn...@gmail.com] Sent: Tuesday, May 31, 2011 7:05 PM To: dev@river.apache.org Subject: correctness, generics, and spaces Hello all, I've been doing some pondering on the question of generics in spaces again. ==Background== To refresh those who've forgotten prior discussion, the proposal was to replace methods like this: Entry read(Entry) With this: T read(T) This change was desired because: 1) it reduces boilerplate code (mandatory casting of objects returned from space) 2) it is a more precise statement of the contract by which these methods operate: i.e. the return type _should be_ the same as the type of the template. Some opposed this change because they felt any use of generics would be seen an implicit guarantee that there are no corner cases with generics. Meanwhile, it was hoped, a lack of generics in the interface would be seen as an implicit warning that no guarantees were made about interactions with generics. Regardless of the API, the current specification does contain corner cases wherein the behavior is potentially surprising. Specifically, this corner case was brought up: If an Entry implementation determines the type of one of its members through a type variable, the returned generic type from a read/take operation would not be guaranteed to be correct if that variable were wildcarded using "null" in a javaspace template search. Given: class Box implements Entry{ public A member; } With the generic implementation of spaces: Box value = read(new Box(5)); //correct Box value2 = read(new Box(null)); //potentially incorrect, inconsistent failures. Box value3 = read(new Box(null)); //correct, but unhelpful. With the non-generic implementation of spaces: Box value = (Box) read(new Box(5)); //correct Box value2 = (Box) read(new Box(null)); //potentially incorrect, inconsistent failures. Box value3 = (Box) read(new Box(null)); //correct, but unhelpful. Note that regardless of whether the implementation includes generic methods, both cases require careful thought in the usage of generics to avoid errors. Because of this, a recommendation was made that Entry object
Re: correctness, generics, and spaces
On 6/1/2011 10:31 AM, James Grahn wrote: ... I am now wondering: is the Gigaspaces code available? Under what license? And is anyone there interested in contributing? ... My understanding is that GigaSpaces is a commercial product, although a limited version is available for free use. See http://www.gigaspaces.com/licensing. For that reason, I am trying to avoid importing into River any code or even ideas from Gigaspaces. Of course, Apache-compatible licensing would change all that. Patricia
Re: correctness, generics, and spaces
On Tue, May 31, 2011 at 10:51 PM, Shay Hassidim wrote: > James, > In case this helps - After similar debates over the years we at GigaSpaces > end up with: > T read(T template) > T take(T template) > write(T entry) Quite interesting. This is exists presently in the experimental generics branch, except the type is . I take this to mean you did not address the corner case that worried many on this list? Does it simply prove to not be an issue in your experience? > See more here: > http://www.gigaspaces.com/docs/JavaDoc8.0/org/openspaces/core/GigaSpace.html > > Please note we support POJO as well with our implementation as space classes > and not just Classes implementing the Entry interface. > This works very well for us. Entry, of course, is just a marker interface. When you say "POJO", though you mean Java objects without any requirements upon them? (e.g. no requirement of a public, no-arg constructor, no need for public fields, etc.) The inclusion of asynchronous calls using Futures is also quite noteworthy, as is your treatment of "snapshot". I was about to start poking the mailing list about snapshot myself, albeit with a different proposal than yours. I am now wondering: is the Gigaspaces code available? Under what license? And is anyone there interested in contributing? > Shay Hassidim > Deputy CTO By the way, welcome! If nothing else, your feedback in discussions will prove valuable, I'm sure. james > -Original Message- > From: James Grahn [mailto:grahn...@gmail.com] > Sent: Tuesday, May 31, 2011 7:05 PM > To: dev@river.apache.org > Subject: correctness, generics, and spaces > > Hello all, > I've been doing some pondering on the question of generics in spaces again. > > ==Background== > > To refresh those who've forgotten prior discussion, the proposal was to > replace methods like this: > Entry read(Entry) > > With this: > T read(T) > > This change was desired because: > 1) it reduces boilerplate code (mandatory casting of objects returned from > space) > 2) it is a more precise statement of the contract by which these methods > operate: i.e. the return type _should be_ the same as the type of the > template. > > Some opposed this change because they felt any use of generics would be seen > an implicit guarantee that there are no corner cases with > generics. Meanwhile, it was hoped, a lack of generics in the > interface would be seen as an implicit warning that no guarantees were > made about interactions with generics. Regardless of the API, the > current specification does contain corner cases wherein the behavior is > potentially surprising. > > Specifically, this corner case was brought up: If an Entry implementation > determines the type of one of its members through a type variable, the > returned generic type from a read/take operation would not be guaranteed to > be correct if that variable were wildcarded using "null" in a javaspace > template search. > > Given: > class Box implements Entry{ > public A member; > } > > With the generic implementation of spaces: > Box value = read(new Box(5)); //correct Box value2 > = read(new Box(null)); //potentially incorrect, inconsistent > failures. > Box value3 = read(new Box(null)); //correct, but unhelpful. > > With the non-generic implementation of spaces: > Box value = (Box) read(new Box(5)); //correct > Box value2 = (Box) read(new Box(null)); > //potentially incorrect, inconsistent failures. > Box value3 = (Box) read(new Box(null)); //correct, but > unhelpful. > > Note that regardless of whether the implementation includes generic methods, > both cases require careful thought in the usage of generics to avoid errors. > Because of this, a recommendation was made that Entry objects should probably > not have a parameterized types in general. > > == Proposal == > > What I finally realized: we can actually require Entries to not contain any > unassigned type parameters. > > Because it is a bad practice regardless, why not do that? > > Costs: > 1) People who are familiar with generics and would always properly handle > corner cases will not be able to do exactly as they please; they would need > to provide a fully specified wrapper class for what would otherwise be their > Entry class. > 2) An additional runtime check of an Entry's class would slow the execution > time of Javaspace methods (slightly). > > Benefits: > 1) If this clears the opposition for using generics in the Javaspace > interface, see the above mentioned benefits. > 2) Prevents violation of the principle of least surprise in using generics > with space (regardless of implementatio
RE: correctness, generics, and spaces
James, In case this helps - After similar debates over the years we at GigaSpaces end up with: T read(T template) T take(T template) write(T entry) See more here: http://www.gigaspaces.com/docs/JavaDoc8.0/org/openspaces/core/GigaSpace.html Please note we support POJO as well with our implementation as space classes and not just Classes implementing the Entry interface. This works very well for us. Shay Hassidim Deputy CTO -Original Message- From: James Grahn [mailto:grahn...@gmail.com] Sent: Tuesday, May 31, 2011 7:05 PM To: dev@river.apache.org Subject: correctness, generics, and spaces Hello all, I've been doing some pondering on the question of generics in spaces again. ==Background== To refresh those who've forgotten prior discussion, the proposal was to replace methods like this: Entry read(Entry) With this: T read(T) This change was desired because: 1) it reduces boilerplate code (mandatory casting of objects returned from space) 2) it is a more precise statement of the contract by which these methods operate: i.e. the return type _should be_ the same as the type of the template. Some opposed this change because they felt any use of generics would be seen an implicit guarantee that there are no corner cases with generics. Meanwhile, it was hoped, a lack of generics in the interface would be seen as an implicit warning that no guarantees were made about interactions with generics. Regardless of the API, the current specification does contain corner cases wherein the behavior is potentially surprising. Specifically, this corner case was brought up: If an Entry implementation determines the type of one of its members through a type variable, the returned generic type from a read/take operation would not be guaranteed to be correct if that variable were wildcarded using "null" in a javaspace template search. Given: class Box implements Entry{ public A member; } With the generic implementation of spaces: Box value = read(new Box(5)); //correct Box value2 = read(new Box(null)); //potentially incorrect, inconsistent failures. Box value3 = read(new Box(null)); //correct, but unhelpful. With the non-generic implementation of spaces: Box value = (Box) read(new Box(5)); //correct Box value2 = (Box) read(new Box(null)); //potentially incorrect, inconsistent failures. Box value3 = (Box) read(new Box(null)); //correct, but unhelpful. Note that regardless of whether the implementation includes generic methods, both cases require careful thought in the usage of generics to avoid errors. Because of this, a recommendation was made that Entry objects should probably not have a parameterized types in general. == Proposal == What I finally realized: we can actually require Entries to not contain any unassigned type parameters. Because it is a bad practice regardless, why not do that? Costs: 1) People who are familiar with generics and would always properly handle corner cases will not be able to do exactly as they please; they would need to provide a fully specified wrapper class for what would otherwise be their Entry class. 2) An additional runtime check of an Entry's class would slow the execution time of Javaspace methods (slightly). Benefits: 1) If this clears the opposition for using generics in the Javaspace interface, see the above mentioned benefits. 2) Prevents violation of the principle of least surprise in using generics with space (regardless of implementation). == Implementation Detail == At the interface level, we would need to add a line to the documentation of Entry, stating that any class implementing Entry may not include type parameters. Entry implementations already have several requirements which can't be enforced at compile time, so adding another is not the worst thing in the world. At the implementation level, we'd add enforcement in outrigger's EntryRep.ensureValidClass, checking to confirm that the Entry that Outrigger is given has no type parameters via reflection. Shouldn't take long to edit the existing generics branch to do this. == Questions == So here are my questions: 1) Is there a problem transforming this from a bad practice to a forbidden practice? 2) Does this address concerns with the generics? Are there any corner cases this will not cover? 3) Any other concerns? Anything I'm not seeing? jamesG
correctness, generics, and spaces
Hello all, I've been doing some pondering on the question of generics in spaces again. ==Background== To refresh those who've forgotten prior discussion, the proposal was to replace methods like this: Entry read(Entry) With this: T read(T) This change was desired because: 1) it reduces boilerplate code (mandatory casting of objects returned from space) 2) it is a more precise statement of the contract by which these methods operate: i.e. the return type _should be_ the same as the type of the template. Some opposed this change because they felt any use of generics would be seen an implicit guarantee that there are no corner cases with generics. Meanwhile, it was hoped, a lack of generics in the interface would be seen as an implicit warning that no guarantees were made about interactions with generics. Regardless of the API, the current specification does contain corner cases wherein the behavior is potentially surprising. Specifically, this corner case was brought up: If an Entry implementation determines the type of one of its members through a type variable, the returned generic type from a read/take operation would not be guaranteed to be correct if that variable were wildcarded using "null" in a javaspace template search. Given: class Box implements Entry{ public A member; } With the generic implementation of spaces: Box value = read(new Box(5)); //correct Box value2 = read(new Box(null)); //potentially incorrect, inconsistent failures. Box value3 = read(new Box(null)); //correct, but unhelpful. With the non-generic implementation of spaces: Box value = (Box) read(new Box(5)); //correct Box value2 = (Box) read(new Box(null)); //potentially incorrect, inconsistent failures. Box value3 = (Box) read(new Box(null)); //correct, but unhelpful. Note that regardless of whether the implementation includes generic methods, both cases require careful thought in the usage of generics to avoid errors. Because of this, a recommendation was made that Entry objects should probably not have a parameterized types in general. == Proposal == What I finally realized: we can actually require Entries to not contain any unassigned type parameters. Because it is a bad practice regardless, why not do that? Costs: 1) People who are familiar with generics and would always properly handle corner cases will not be able to do exactly as they please; they would need to provide a fully specified wrapper class for what would otherwise be their Entry class. 2) An additional runtime check of an Entry's class would slow the execution time of Javaspace methods (slightly). Benefits: 1) If this clears the opposition for using generics in the Javaspace interface, see the above mentioned benefits. 2) Prevents violation of the principle of least surprise in using generics with space (regardless of implementation). == Implementation Detail == At the interface level, we would need to add a line to the documentation of Entry, stating that any class implementing Entry may not include type parameters. Entry implementations already have several requirements which can't be enforced at compile time, so adding another is not the worst thing in the world. At the implementation level, we'd add enforcement in outrigger's EntryRep.ensureValidClass, checking to confirm that the Entry that Outrigger is given has no type parameters via reflection. Shouldn't take long to edit the existing generics branch to do this. == Questions == So here are my questions: 1) Is there a problem transforming this from a bad practice to a forbidden practice? 2) Does this address concerns with the generics? Are there any corner cases this will not cover? 3) Any other concerns? Anything I'm not seeing? jamesG