Git Product home page Git Product logo

Comments (6)

andymcn avatar andymcn commented on May 19, 2024

I have another possible solution.

In such situations (which we can spot reasonably easily) we could give the class an extra wrapper function that boxes the arguments and then calls the real function. Using the example from the original comment:

  1. Class Foo has a method bar$ which takes a Stringable argument and has the function body the programmer provides.
  2. Class Foo also has a method bar which takes a U32 argument. All this does is box the argument and then call bar$.
  3. When we have a trait T (which may or may not be a Foo) we just call bar() normally with an unboxed U32. If the object is a Foo then the U32 will be boxed and passed to bar$().
  4. When we have something that we know is a Foo we call bar$() with a boxed argument.

This is roughly equivalent to rewriting Foo as:

class Foo is T
  fun ref bar(x: U32) => bar$(x.box())
  fun ref bar$(x: Stringable) => ...  // Original body

from ponyc.

sylvanc avatar sylvanc commented on May 19, 2024

With a trickier example:

interface S1
  fun ref m(x: U8)

interface S2
  fun ref m(x: U16)

trait T1
  fun ref m(x: U32)

trait T2
  fun ref m(x: U64)

class C is T1, T2
  fun ref m(x: Stringable) => ...

What would be the vtable entries for the different functions? Would the painter be able to distinguish at the call site? That is, if we have:

var c = C
var s1: S1 = c
var s2: S2 = c
var t1: T1 = c
var t2: T2 = c

s1.m(0)
s2.m(0)
t1.m(0)
t2.m(0)

...we need 4 different vtable entries to handle that, since the 0 will be of four different bit widths.

from ponyc.

andymcn avatar andymcn commented on May 19, 2024

Interesting. Yes this scheme could still work with such an example (and indeed with traits that expand on methods from other traits) it's just a little fiddly.

What I'm talking about here is effectively overloading methods by type, purely internally, not exposed or available to the programmer. I think there are 2 basic options for handling this. We could make the painter aware of primitive types and boxing, but I don't think that's a good way to go.

I think the better approach is to keep the painter exactly as it is and use a form of name mangling. So in the example from the previous comment C would have 5 different "m" methods:

class C is T1, T2
  fun ref m$U8(x: U8) => m$boxed(x.box())
  fun ref m$U16(x: U16) => m$boxed(x.box())
  fun ref m$U32(x: U32) => m$boxed(x.box())
  fun ref m$U64(x: U64) => m$boxed(x.box())
  fun ref m$boxed(x: Stringable) => ...

We then call different versions of m at different call sites based on the type of the receiver we have there:

var c = C
var s1: S1 = c
var s2: S2 = c
var t1: T1 = c
var t2: T2 = c

s1.m(0)  // s1.m$U8(U8(0))
s2.m(0)  // s2.m$U16(U16(0))
t1.m(0)  // t1.m$U32(U32(0))
t2.m(0)  // t2.m$U64(U64(0))

This does mean that types S1, S2, T1 and T2 are "infected" and always need to use the mangled names. This presents no implementation problems for either vtables or call sites, the only problem is detecting and propogating the requirement to mangle. We could choose to always mangle all names. We can also correctly detect when it's needed, it just requires the full program type analysis that we need to do at some point anyway.

from ponyc.

sophiaIC avatar sophiaIC commented on May 19, 2024
  1. Disallow contravariance with primitive types. Nasty.

Do you have examples where the contravariance (whether primitive or not) in traits is useful?

from ponyc.

sylvanc avatar sylvanc commented on May 19, 2024

In pony, types with different type parameters don't have a subtype relationship. So, given:

trait Animal

class Wombat is Animal

Array[Animal] and Array[Wombat] are not related types. This makes them type safe, unlike Java, but since we don't have per-type parameter variance annotation, if we stopped here we would be missing out on some things, such as passing an Array[Wombat] where an Array[Animal] is expected if we know they will be read, but not written (which would be type safe).

However, with contravariant parameters and covariant results, we can. Here, I craft two type aliases for structural types that allow me to read elements from anything that looks like a sequence:

interface SequenceReader[A]
  fun box apply(i: U64): this->A

interface SequenceWriter[A]
  fun ref update(i: U64, v: A)

Now, Array[Wombat] is a subtype of SequenceReader[Animal], without being a subtype of Array[Animal], because fun box apply(i: U64): this->Wombat is a subtype of fun box apply(i: U64): Animal since the parameter types are contravariant (in this case, equal) and the return type is covariant.

Similarly, Array[Animal] is a subtype of SequenceWriter[Wombat] without being a subtype of Array[Wombat], because fun box update(i: U64, v: Animal) is a subtype of fun box update(i: U64, v: Wombat) since the parameter types are contravariant and the return type is covariant (in this case, equal).

So trait method parameter contravariance and return type covariance gives us all the power of a subtype relationship between types with different formal parameters without the type safety problem (Java) or complex annotation (Scala: http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/ ).

from ponyc.

sylvanc avatar sylvanc commented on May 19, 2024

This applies to interfaces as well as traits, which makes a compile time solution even trickier. For now, until we think of something better, is_fun_sub_fun() checks for super type parameters that are machine words, and requires that they are invariant rather than contravariant.

Return types and receiver types are unaffected.

from ponyc.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.