New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parameter of type Object matches first type of Cell<T> regardless of T's type #802
Comments
Ah, this is a nice one. Basically the matches against types are calls to instanceOf? (or inheritsFrom?, not too sure, depends on whether they are called on the object or its class, either way the bug is the same) but all instanceOf? does is recursively check the class, class super (etc...) against the type provided. That means that generic types are never checked against, only the base type. @fasterthanlime, any thoughts? |
The parameter that 'instanceOf?' receives doesn't have generic type A nested match on 'T' is not too much hassle On Tue, Aug 19, 2014 at 3:05 PM, Alexandros Naskos <notifications@github.com
|
Although almost impossible to change now would it not be better to have the class store the type variable instead of every object and create a separate class at runtime for every combination of type variables? |
Hmm yes, indeed, the Class instancehas no information on the generics. The way ooc generics work, I think it actually makes sense that the instance variable contains the generic information rather than building a separate metaclass for each combination used (why not do templates at that point?), however we do run into this issue... |
Anyway, I think a warning is the way to go at that point, perhaps this could be reconsidered in the future when I start oc (I intend to fully document every feature, the runtime and its C implementation at that point). |
And the current solution bloats all instances of a generic type. |
Actually, I think it would be possible to hack something together. Rather than changing where the information on generics is held and instaceOf? / inheritsFrom?, we could add conditions checking the generic types on case clauses that have generic types. E.g. case c: Cell<String> =>
// becomes
case c instanceOf?(Cell) && c T instanceOf?(String) =>
// rather than
case c instanceOf?(Cell) => |
@Shamanas: it's a language-level feature, not a compiler-level feature. Right now, the language says (although, again, we have no proper spec) that It also says you can explore a generic type instance's type parameters via I've wanted to build more introspection into ooc for a long while but it's Another solution would be an ad-hoc solution, such as a linked list (not On Tue, Aug 19, 2014 at 3:31 PM, Simon Mika notifications@github.com
|
That is a cleaver solution that does not break anything, almost at least. Is it possible to also support the following: case c: Cell<_> =>
// becomes
case c instanceOf?(Cell) => |
Or maybe this would do (if it is not possible to create another type Cell): case c: Cell =>
// becomes
case c instanceOf?(Cell) |
@fasterthanlime @simonmika Edit: Nope, it doesn't, it seems it is imposed that generic types are complete |
Doesn't case: Cell => already work? then you can access 'case T' - that's what I was hinting at in my first The difference with (case instanceOf?(Cell)) is that match with a variable On Tue, Aug 19, 2014 at 3:43 PM, Alexandros Naskos <notifications@github.com
|
@fasterthanlime Yeah, it is still possible to achieve this by matching against Cell<Object> and then a match/if for c T but I think it makes sense for match to be able to do that automatically and cast to the correct type which as you said is the nice thing about this syntax. |
No this fails at compile time: write: func(data: Object) {
(match (data) {
case cell: Cell =>
cell get()
case =>
"FAIL"
}) println()
}
write(Cell new(2)) With the following error:
|
So what do you reckon the final verdict is? |
I honestly don't know. However, there should be a way to match a type that has generic parameters On Wed, Aug 20, 2014 at 5:36 PM, Alexandros Naskos <notifications@github.com
|
Ok so warning + make case foo: Foo => ... acceptable, when Foo has generic parameters. |
I was thinking perhaps Foo<?> just to make sure. Not sure. On Thu, Aug 21, 2014 at 10:20 AM, Alexandros Naskos <
|
Yeah, that makes sense to indicate the type is generic but it means special variable definition grammar for case clauses. |
@fasterthanlime match obj {
case c: Cell<type> =>
// c is now the Cell variable, type is now c T
match type {
// ...
}
} This would also allow for Foo<_> syntax when we don't need to access the type, since _ is a valid identifier. |
Can you give an actual example that allows me to match on the write: func <T> (data: Object) {
(match (data) {
// "case value: Cell =>" won't build because "No type parameters for Cell. It should match Cell",
// as already mentioned, so doing "Cell<Object>" instead
case value: Cell<Object> =>
(match (value T) {
case valTee: String =>
value get()
case valTee: Int =>
value get() toString()
})
case =>
"FAIL"
}) println()
} This won't build because "No such function toString() for case value: Cell<String> =>
(match (value T) {
case valTee: String =>
value get()
case valTee: Int =>
value get() as Int toString() I instead get the error Ok, so let's ignore the function that takes an Object for now, and try something simpler: A function that takes write: func <T> (data: Cell<T>) {
(match (data T) {
case value: String =>
data get() as String
case value: Int =>
data get() as Int toString()
case =>
"FAIL"
}) println()
}
write(Cell new(2)) // prints "FAIL"
write(Cell new("Hello")) // also prints "FAIL" Well, that didn't work. What about write: func <T> (data: Cell<T>, t: T) {
(match (data T) {
case value: String =>
data get() as String
case value: Int =>
data get() as Int toString()
case =>
"FAIL"
}) println()
} Well, |
It's kind of hard to read through all that so it's entirely possible that I missed soemthing, but I noticed something. You can either do cell: Cell<T>
match (cell T) {
case Int =>
i := cell get() as Int
case Float =>
f := cell get() as Float
} (which is long-form), or you can do the short form: cell: Cell<T>
match (cell get()) {
case i: Int =>
// whatever
case f: Float =>
// whatever
} But above, you're conflating the two, so there's no chance it'll work :) Generic values & generic types aren't the same thing. |
@davidhesselbom here's a full example that works well for me: Whatever: class { init: func }
write: func ~noCell <T> (t: T) {
write(Cell new(t))
}
write: func <T> (cell: Cell<T>) {
match (cell get()) {
case i: Int =>
"Got int #{i}" println()
case f: Float =>
"Got float #{f}" println()
case =>
"Got other type #{cell T name}" println()
}
}
write(42 as Int)
write(3.14 as Float)
write(Whatever new()) |
(And indeed, it's a pity that the second |
Splendid, thank you sir! |
No problem. Sorry it took a long-ass issue for this info to get out. It'd be probably right at home somewhere at https://github.com/fasterthanlime/ooc-lang.org/blob/master/content/docs/lang/generics.md, perhaps in a more documentation-y formulation. If someone has time, don't hesitate to send in a pull request. |
I'll look into it. Meanwhile, I gave you another, much smaller one :) |
So, matching the actual typeArgs should be another issue (if at all), but matching generic types without specifying typeArgs at all is now possible. |
outputs
The text was updated successfully, but these errors were encountered: