ponylang / ponylang/ponyc

Calling by method name on a union of distinct types with distinct capabilities.

Open
#3,003 4 comments 0 reactions 0 assignees View on GitHub
help wanted
Dominant language
Pony
Stars
6.2k
Forks
437
Avg merge
7h 14m
Merged PRs (30d)
161

Description

I was doing some brainstorming about a common interface for "byte writers" that would cover both `class ref` and `actor tag` implementations of methods for writing out bytes. I quickly figured out that I couldn't have the same interface cover both cases, but I thought a type union of two interfaces could work well, so I created `OutClass` and `OutActor` interfaces, and called the union of them `Out`:

```pony
type Out is (OutActor tag | OutClass ref)

interface tag OutActor
be print(string : String)

interface ref OutClass
fun ref print(string : String)

class StringWriter is OutClass
var _string: String iso = recover String end

fun ref finish(): String iso^ => _string = recover String end
fun ref print(string : String) =>
_string.append(string)

actor Main
new create(env: Env) =>
let out_1: Out = env.out
out_1.print("Hello, world!")

let out_2: Out = StringWriter
out_2.print("Hello, world!")
try env.out.print((out_2 as StringWriter).finish()) end
```
Doing so gives this error output:
```
Error:
main.pony:19:16: receiver type is not a subtype of target type
out_1.print("Hello, world!")
^
Info:
main.pony:19:5: receiver type: (OutActor tag | OutClass ref)
out_1.print("Hello, world!")
^
main.pony:7:3: target type: (OutActor ref | OutClass ref)
fun ref print(string : String)
^
main.pony:1:14: OutActor tag is not a subtype of OutActor ref: tag is not a subcap of ref
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: OutActor tag is not a subtype of OutClass ref: tag is not a subcap of ref
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: OutActor tag is not a subtype of any element of (OutActor ref | OutClass ref)
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: not every element of (OutActor tag | OutClass ref) is a subtype of (OutActor ref | OutClass ref)
type Out is (OutActor tag | OutClass ref)
^
Error:
main.pony:22:16: receiver type is not a subtype of target type
out_2.print("Hello, world!")
^
Info:
main.pony:22:5: receiver type: (OutActor tag | OutClass ref)
out_2.print("Hello, world!")
^
main.pony:7:3: target type: (OutActor ref | OutClass ref)
fun ref print(string : String)
^
main.pony:1:14: OutActor tag is not a subtype of OutActor ref: tag is not a subcap of ref
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: OutActor tag is not a subtype of OutClass ref: tag is not a subcap of ref
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: OutActor tag is not a subtype of any element of (OutActor ref | OutClass ref)
type Out is (OutActor tag | OutClass ref)
^
main.pony:1:14: not every element of (OutActor tag | OutClass ref) is a subtype of (OutActor ref | OutClass ref)
type Out is (OutActor tag | OutClass ref)
^
```

Note that if I change the code to use the specific interface rather than the type union, everything works okay:
```pony
actor Main
new create(env: Env) =>
let out_1: OutActor = env.out
out_1.print("Hello, world!")

let out_2: OutClass = StringWriter
out_2.print("Hello, world!")
try env.out.print((out_2 as StringWriter).finish()) end
```
```
Hello, world!
Hello, world!
```

Contributor guide

Open the contributing guide

Research direction

Start with the minimal Pony example in the issue and inspect how the compiler resolves method calls on unions with differing capabilities. Define the expected behavior for OutActor tag | OutClass ref and capture it in a regression test; the issue does not name source files or existing tests.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.