Comments (6)
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:
- Class Foo has a method bar$ which takes a Stringable argument and has the function body the programmer provides.
- Class Foo also has a method bar which takes a U32 argument. All this does is box the argument and then call bar$.
- 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$().
- 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.
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.
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.
- Disallow contravariance with primitive types. Nasty.
Do you have examples where the contravariance (whether primitive or not) in traits is useful?
from ponyc.
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.
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)
- Dependent default types HOT 4
- x86 Mac OS Sonoma Compile Error with XCode 15 and HOT 21
- Backend null in epoll during CI run HOT 3
- Non-sendable data seen as sendable
- Release 0.57.1 HOT 2
- Generic parameter when copying a trait method into an object that has a generic parameter of the same name HOT 2
- return usage in disposing block's is flawed and we need to revist. HOT 5
- Slow compare to elixir in `ring benchmark` HOT 2
- Clean up MacOS platform version setting HOT 1
- Release 0.58.0 HOT 1
- Release 0.58.1
- Invalid LLVM generated HOT 1
- Segmentation fault when ponyc compiles this code HOT 2
- Compile fails verification "GEP base pointer is not a vector or a vector of pointers" HOT 13
- LLVM mangling error with `powi` HOT 4
- Release 0.58.2
- Constrained Types RFC
- Segfault from bad cap in code
- Release 0.58.3
- Release 0.58.4 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ponyc.