Design decisions: forward reference, corralling, method keys
Robert Field
robert.field at oracle.com
Mon May 18 17:04:48 UTC 2015
Resend...
On May 13, 2015 5:54:11 PM Robert Field <robert.field at oracle.com> wrote:
> Feedback needed, read on...
>
> The original design decision, see the JEP, was that methods bodies and,
> within classes, method bodies and field initializers could have forward
> references. This kind of forward reference is handled by corralling
> the method or initializer -- meaning that the new definitions with
> unresolved references can be referenced by other code without error or
> unresolved reference. Then at runtime, attempts to execute the
> corralled code causes an UnresolvedException .
>
> However, I've heard loud complaint that only this is too restrictive.
> That forward reference in signatures is important. That, for example,
> it is important to be able to be able to paste definitions from the
> body of a class in the order they appear. That:
>
> class B extends A {}
> class A {}
>
> should be legal.
>
> This motivation is well founded, and there are other correlated
> changes/observations that align with this, that an existing declaration
> can have signature failures on update or that the above can be declared
> first A then B, but then A can be dropped, and that these motivated the
> introduction of JShellState.Status (below).
>
> Thus, new definitions which cannot be corralled (ActiveCorralled) can
> be put in ActiveFailed status, so that, unlike corralled, there is no
> definition defined,so it can't be used by other input without error
> (which, depending on context, may be corralled or failed). However, it
> is still active which means on update it can become active. As an
> example from the tool:
>
> -> class B extends A {}
> | Error:
> | cannot find symbol
> | symbol: class A
> | class B extends A {}
> | ^
> | Added class B, however, it cannot be referenced until the above
> errors are resolved
>
> -> class A {}
> | Added class A
>
> -> new B()
> | Expression value is: B at 5ecddf8f
> | assigned to temporary variable $1 of type B
> This can and should be made prettier by reporting the unresolved inline
> in the message (similarly to the corralled case), but it gives the idea.
>
> But using this new status (ActiveFailed) widens the envelope and
> introduces some new issues, two are known so far:
>
> (A) Thanks, Andrei, for pointing this out. If a variable with
> initializer is in ActiveFailed an update can move it to Active. What
> is the value of the variable? Should the initializer be run? If the
> initializer was the location of the unresolved, it seems silly not to
> run it. Yet, this would be running arbitrary code on update which is
> sure to have surprising behavior in some cases. Here are the not so
> perfect options as I see them:
>
> Disallow forward reference in variables. This violates the
> desired "paste from class body" thinking. Disallow forward reference
> in variables with initializers. This still violates "paste from
> class body", and it is strangely asymmetric. Give the
> variable the default value which is what is the currently
> specified behavior for Replaced updates to a variable, but it is
> odd that the initializer never gets executed, and what if it was
> the cause of the unresolved? Run the initializer at update time. In
> some cases this could cause output, hangs, or arbitrary
> side-effects. Choosing this would require re-examining execution
> on update in all cases. Use RejectedFailed if the
> initializer has unresolved references. Otherwise (variable type
> unresolved) run the initializer and store the result on update
> when update turns it active. This has many problems including
> the initializer result type would in almost all cases need to be
> the variable type (which is unresolved) or null.
> (B) The key for classes and variables is determined by just their name.
> But because of overloading, for methods, the key is the name plus the
> parameter types. This is fine if the method signature can be compiled
> (the body can be stubbed-out as is the case when corralled), as the
> full qualified name of the parameter types is then known. But if one
> of the parameter types is unresolved its full name is not known either
> so the correct key cannot be determined. This is significant because
> if it is put in ActiveFailed it can updated into Active (or
> ActiveCorralled) at which point its actual key is then known and a
> central invariant is that the key for an input does not change, And
> here is another set of non-ideal options that I can think for this:
>
> Disallow forward reference on method parameter types. This
> violates the desired "paste from class body" thinking. Assume any
> unresolved reference in parameter types to be a top-level REPL
> type. That is, that it will be defined by an entered class
> definition. If that name gets defined by an import it won't see
> it. Change the definition of key so that it is defined by the
> name and UNqualified type names of the parameters. This
> should work cleanly but it breaks compatibility with Java
> semantics (something we trying very hard not to do), if only in a
> very small way -- because it would mean that given a defined
> method m(foo.Bar x), entering m(baz.Bar x) would replace rather
> than overload m(foo.Bar x).
> Throw away the invariant. Modify the key, oh the issues with
> that! Or mark the key dropped on resolving update adding a new key..
> Reasoned opinions and options I did not consider hereby solicited.
>
> Thanks,
> Robert
>
> public static enum JShellState.Status Enum Constant and Description
> Active
> Active: a snippet which is in valid form and can be used by
> new snippets (if a declaration or import), and can be
> executed (if it is executable).
> ActiveCorralled
> ActiveCorralled: a declaration snippet with unresolved
> references or other issues.
> ActiveFailed
> ActiveFailed: a declaration snippet failed compilation on
> update in a way that cannot be corralled -- signature failure.
> Dropped
> Dropped: a declaration snippet was explicitly dropped by a
> call to the JShellState.drop().
> RejectedFailed
> RejectedFailed: a snippet failed compilation on initial
> evaluation.
>
More information about the kulla-dev
mailing list