3.8 KiB
3.8 KiB
Dynamic Types
Goal
Interoperability with native JavaScript
Examples
Unbounded dynamic type:
fun jsFun(p: dynamic): dynamic
TODO
- Dynamic functions?
- what is the default return type?
- Can we omit
returnexpressions when the return type isdynamic? - Can we return
Unitwhen return type isdynamic?
- Dynamic classes/traits?
- All members are implicitly
dynamic - All types whose type constructors are marked
dynamicare themselves dynamic types
- All members are implicitly
- Bounded dynamic types
Typing rules
dynamicis assignable to anything- everything is assignable to
dynamic dynamicvariable may holdnulldynamic?is the same asdynamic, a warning should be issuedlub(T, dynamic) = dynamic- ???
glb(T, dynamic) = T dynamiccan't be substituted for reified parameters of function/constructor calls (this means that it's not possible to create an array ofdynamic)dynamiccan't be used as a supertype or upper bound for a tpe parameterdynamicis less specific than any other type
Syntax
type
: ...
| "dynamic"
;
"dynamic" is a soft keyword:
- if it occurs in a non-type context, it's an identifier
- in a type context, when followed by a dot (except for a dot that separates a receiver type from a function/property name) or an angle bracket
<, it's an identifier - on the left-hand-side of
::in a callable reference:dynamic::fooimplies thatdynamicthere is a normal identifier
Representation
Internally, dynamic is represented as a flexible type Nothing..Any?, with the following capabilities:
- makeNullable has no effect
- (???) makeNotNull changes it to a non-null version:
Nothing..Any - if a receiver of a call is dynamic (or a dynamic implicit receiver is available), and the call can not be resolved statically (no fitting candidates are found, NOTE: this does not include ambiguity), a dynamic candidate descriptor is created for the arity of the call, and the call is resolved to it.
- (???) All methods of JetType are delegated to the upper bounds, instead of lower bound
Implications
Nothing being mentioned, there's a risk of taking dynamic for a bottom type in some contexts, this is not intended and should be tested carefully.
Resolution rules
- If a receiver is
dynamica call is resolved as dynamic if no members match the signature (these are members ofAny, unless we implement boundeddynamic)- Motivation: otherwise, any extension to any type that simply happens to be in scope and match the name and arguments
will be bound for a call with a
dynamicreceiver, i.e. there's no way to force a call to be dynamic, and in the case of a*-import the code may change its semantics just because somebody added some extension in another file. - This means that an extension can not be called on a
dynamicreceiver. If needed, one can force a call to an extension by casting teh receiver to a static type:(d as Foo).bar() - This also means that an extension whose receiver type is
dynamiccan not be called on adynamicvariable without a cast
- Motivation: otherwise, any extension to any type that simply happens to be in scope and match the name and arguments
will be bound for a call with a
Type Argument Inference
When expected type of a call is dynamic, it does not automatically provide type arguments for nested calls.
Example:
fun foo(d: dynamic) {...}
foo(listOf()) // can't determine T for listOf<T>()
Discussion:
- we could tweak inference so that it takes
dynamicas a bound for all type variables whose containing type has a dynamic bound, but it's hard to be sure it's worth the while
Notes
- dynamic types are not supported on the JVM back-end
- dynamic types are forbidden on the right-hand side of
is,!is,asandas?(but not as generic arguments, e.g.x is List<dynamic>is allowed)