ponylang / ponyc

Pony is an open-source, actor-model, capabilities-secure, high performance programming language
http://www.ponylang.io
BSD 2-Clause "Simplified" License
5.74k stars 415 forks source link

Should object literals be lifted to actors when their subtyping includes behaviors? #2855

Open patternspandemic opened 6 years ago

patternspandemic commented 6 years ago

Should object literals resulting in an anonymous class or primitive be promoted to actor literals when they are sub-typed with an interface or trait including a behavior? As it is now, the literal must also include a behavior to be considered an actor literal. Note that it does not matter whether the trait or interface includes a default implementation for such behaviors.

I would expect such literals to be lifted to an actor, given any trait or interface requiring any behaviors also intends to categorize an actor. Then again, I'm unsure what kind of consequences this entails with union or intersected sub-typing.

ponyc version:

0.24.4 [release]
compiled with: llvm 3.9.1 -- cc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
Defaults: pic=false ssl=openssl_0.9.0

source (run in playground):


trait WithBehavior
  be bar() => None

actor Main
  new create(env: Env) =>

    let actor_literal =
      object is WithBehavior
        // Inclusion of behavior lifts to actor literal
        be other() => None
      end

    // Error: cannot add a behaviour (bar) to a primitive
    let primitive_literal =
      object is WithBehavior end

    // Error: cannot add a behaviour (bar) to a class
    let class_literal =
      object is WithBehavior
        var some: String = "field"
      end
plietar commented 6 years ago

The straightforward solution is to look in all declared interfaces and traits for behaviours when deciding whether the literal should be an actor/object/primitive.

However I do find it surprising that the kind of "entity" being created is implicit. I would prefer if a different keyword was used, eg:

actor Main
  new create(env: Env) =>
    let actor_literal = actor is WithBehavior end
    let primitive_literal = primitive is WithBehavior end

This unfortunately makes parsing ambiguous, since the actor keyword could be either a literal, or the start of a new actor definition. It can be disambiguated by looking at the next token (if it's an identifier then it's a definition, if it's is/let/var/fun/be/end it's a literal, but that might be too confusing.

(I've always disliked how "actor" refers to both the definition and the runtime entity, unlike the existing distinction between class/object, but I was never able to come up with a better name for either).

jemc commented 6 years ago

The straightforward solution is to look in all declared interfaces and traits for behaviours when deciding whether the literal should be an actor/object/primitive.

Yeah, I think that's what we should do for now.

Regarding other syntax suggestions, I think stuff like that would have to be tackled in a separate RFC outside this scope.