From: David C. <dc...@us...> - 2012-07-11 19:56:47
|
This is a writeup of some of my thoughts relating to (parts of) yesterdays discussion. Right now it is possible to write code that only makes sense in the managed backend (e.g. M3R Hadoop compatability layer), the question is what exactly is allowed when you want to target both backends (writing portable X10). (As an aside, it would be good to have a compiler switch that would throw a front end error if the code is not portable. Currently such code compiles fine in the managed backend and causes post compiler errors in the native backend.) This is coming up right now in the context of exception handling. If we are fixed on a design where there are 2 roots to the exception hierarchy (it seems this is necessary because otherwise the managed runtime would have to have x10.lang.Throwble be @NativeRep("java.lang.Throwable") and thus a checked exception) then we have the following options: The simplest (and current) definition no types that come from pre-existing class files (or java standard library) are allowed in portable X10. This makes it hard to write frameworks that can execute user code, such as this one: class FrameWork { static interface Job { def run () : void; } def runJob (j:Job) : Throwable { // asynchronously run j somehow, catching any errors if (j.ranOK()) return null; return j.exception(); } } Examples of this pattern are: * XRX implementations of at, async, next, perhaps some others * PlaceLocalHandle.make * M3R core engine (must catch all exceptions to avoid barrier deadlock) * Some sort of resillient 're-execute this code' framework? * potentially some high level user code? Effect 1 Anyone using this library in an interop context must catch java.lang.Error and java.lang.Runtime exception and package them in their own ExceptionWrapper class that extends x10.lang.Throwable. Otherwise the exceptions will 'escape' . You don't even get an error when this happens, you usually get a deadlock or some other bizarre behaviour. It could be argued that since managed X10 allows interop, that all frameworks that have this property are error-prone unless compiled natively. Effect 2 You have to catch and package all your checked exceptions too, because Job.run does not have a @Throws annotation. If you do this, you are also accounting for effect 1, because you have to catch java.lang.Throwable which includes the unchecked exceptions from effect 1. Alternative -- allow java types in catch clauses The type-theoretical point here is that in native X10, instances of such types will not arise so the whole block can be ignored at codegen time. It would be possible for a predetermined (and documented) list of types to be available, i.e. probably java.lang.Throwable, java.lang.Error, java.lang.RuntimeException and maybe some others. This means that we can simply provide these types in the XRC runtime and existing codegen works fine. That makes implementing this a 5 minute job. This permits using @Throws and catching and rethrowing java.lang.Throwable, which allows the above code to be rewritten: class FrameWork { static interface Job { def run () : void @Throws[java.lang.Throwable] ; } def runJob (j:Job) : Any { // Any is the only type that is above both java.lang.Throwable and x10.lang.Throwable // asynchronously run j somehow, catching all kinds of possible errors if (j.ranOK()) return null; return j.exception(); } } Effect User doesn't have to worry about effect1 and effect2 from the previous section. Note This is actually possible right now using @Native blocks to stop code reaching the native backend, but such code is ugly. We could use it inside XRX classes but it should not be the story for our users. So we don't have to do this if we believe that examples of the above framework will not occur in user code and we don't mind writing ugly difficult code ourselves instead of going for a language solution. Even more power but harder to implement We can actually allow all sorts of references to java types in portable code, as long as these uses are only for threading. I.e. we do not extend, implement, access static methods / fields, or create new instances of such types. We can, however, take parameters of such types, define variables and assign such values, and rethrow them. In fact I think for mixed mode some degree of this will actually be *necessary* because both managed and native 'sides' of the computation will be run through the same frontend and will reach both backends. This requires the codegen on the native side to cleverly ignore such types. E.g instanceof MyJavaClass is always false. Casting always fails, etc. The only value of such a type in the native backend is null, which could be used for optmisations. But 99% of the time this will just be code that is part of a larger portable program but is never even executed on the native backend, but has to be present because it is needed on the managed backend. |