question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Dynamic assignments to union and intersection types

See original GitHub issue

I’ll use the following declarations in this issue:

dynamic X { shared formal String x; }
dynamic Y { shared formal String y; }

This code doesn’t work:

X|Y xy;
dynamic { xy = dynamic [y = "y";]; }

try online

The compiler completely ignores the union type and treats it like an assignment to type X. The possibility that the correct type might be Y, and that it should check for Y’s members too, is completely ignored.

This code does work:

X&Y xy;
dynamic { xy = dynamic [x = "x";]; }

try online

Again, the compiler ignores the intersection type, and only checks assignability to the first type. y remains undefined; attempting to use it (which, to the typechecker, is perfectly legal) can result in a nasty surprise.

The first case (union type) is problematic because, in general, it’s impossible to tell which type of the union is the right one. Which type should this assign to the value?

X|Y xy;
dynamic { xy = dynamic [x = "x"; y = "y"; z = "z";]; }
  • X? But why X and not Y?
  • Y? Same question.
  • X|Y? This breaks a coverage/enumeration guarantee of the language: a switch with cases is X and is Y is exhaustive because X|Y (union of case types) covers X|Y (switched type), but here our value is neither X nor Y.
  • X&Y? This seems intuitively natural, but I don’t know how the typechecker would arrive at this type. I also doubt that such a solution exists for every similarly problematic situation. This also breaks the contract of ceylon.language.meta::type and violates a language guarantee of §8: “In Ceylon, every value is a reference to an instance of a class”.

The second case (intersection type) is less problematic, but the issue of the value not having a non-composite type remains.

Issue Analytics

  • State:open
  • Created 7 years ago
  • Comments:15 (15 by maintainers)

github_iconTop GitHub Comments

1reaction
lucaswerkmeistercommented, Aug 2, 2016

I propose that both assignments should be disallowed. Instead, force users to write code like this:

X|Y xy;
dynamic {
    xy = dynamic [y = "y";] of Y;
    // or:
    if (...) {
        X x = dynamic [x = "x";];
        // do stuff with x
        xy = x;
    } else {
        Y y = dynamic [y = "y";];
        // do stuff with y
        xy = y;
    }
}
dynamic MyXY satisfies X & Y {}

X&Y xy;
dynamic {
    xy = dynamic [x = "x"; y = "y";] of MyXY;
    // or:
    MyXY mxy = dynamic [x = "x"; y = "y";];
    // do stuff with mxy
    xy = mxy;
}
0reactions
chochoscommented, Aug 14, 2016

It’s relatively easy to fix for intersection types: the object simply has to contain the members of all the types in the intersection. Although probably an anonymous type would have to be created at runtime, which could create problems if metamodel is used on it.

Union types are tricky though, and don’t even seem to make sense for dynamic objects. I don’t know if it can be disallowed on the typechecker; otherwise it would have to be disallowed at runtime.

Now, if we change the way this whole thing works and instead of dressing the objects we simply let them go and make is check for members on dynamic objects, the way dre$$ currently does, then assigning dynamic objects to union/intersection types would work just fine. I don’t see how this will break binary compat, since the dre$$ function will still exist, but will only check the members without actually adding type info to the object, and so can also be used inside is. Perhaps this would be the best way to go; it makes sense in this context. But I can’t remember right now if there were other reasons why the object needed to be dressed up at the site of assignment; probably something to do with leaking untyped objects from dynamic blocks, even if they are checked to see if they have the required members to pass for some typed object…

Read more comments on GitHub >

github_iconTop Results From Across the Web

TypeScript Advanced Types: Union and Intersection
In this article, we'll look at intersection and union types. ... name but different type, then it's automatically assigned the never type, ...
Read more >
Type Assignment for Intersections and Unions in Call-by ...
We develop a system of type assignment with intersection types, union types, indexed types, and universal and existential depen- dent types that is...
Read more >
Chapter 4: Union and Intersection Types - HackMD
To illustrate the concepts of union and intersection types, we work on a page for tech events: Meetups, conferences, webinars. Events that are...
Read more >
Handbook - Unions and Intersection Types - TypeScript
A union type describes a value that can be one of several types. We use the vertical bar ( | ) to separate...
Read more >
Union and intersection types to support both dynamic and ...
A new interpretation of union and intersection types allows statically gathering the type information of dynamic references, which improves ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found