Open nspark opened 7 years ago
@mppf: Tagging you to make sure you see this issue.
I tried making some simple modifications to function resolution to address Part 1 and Part 2, but the result was something that was very fragile - it got Part 1 to work as-written but wouldn't work if there were any user-defined constructors.
I expect that the example in Part 1 should work once we get the compiler-generated initializer using the new style. It is challenging to make it work correctly with the current old-style compiler-generated constructor. (The problem is that the old-style ctor doesn't pass the type to be constructed in - but the new-style will do that as part of the "meme" argument).
For the example in Part 2, if you added
proc A.A(a, T=a.type) { this.a = a; }
we would have that example reduced to the case in Part 1. (And there will be a way to do this with new-style initializers too). The issue there is that the initializer for C takes in two arguments: type T and value a. With the new-style initializers, there won't necessarily be the trivial relationship between type fields and type arguments in the constructor call. Except for the compiler-generated constructor where they would be the same. So I could get exactly what you wrote in Part 2 to work for compiler-generated constructors if we basically had the compiler add the int
argument to the new C
call. My attempt at implementing that would make new C(int, 1)
no longer work, which I think is problematic. I'm thinking it's probably a better idea to just write the 1-argument initializer anyway. Adding the 1-argument initializer would let you write new A(1)
as well.
For Part 3, you might be interested in PR #5058 which is a start at adding a forwarding feature. The main thing that effort needs is further design discussion. In particular it needs more agreement on the general direction of the feature and also on the name 'delegate'. I got pretty far in implementing it but have set it aside for now as I no longer view it as necessary for writing things like reference-counting records to avoid needing to write delete
.
Tagging @lydia-duncan on this issue due to the relationship to initializers and particularly generic initializers.
(lurking, nothing to add just yet)
For now, this is issue blocked by initializers development. For lack of a better label, I marked this aswork in progress
to indicate this.
Tracking for the initializers implementation lives in #5198
As an additional datapoint -- this feature would be useful toLayoutCS
(#6936) by enabling a less verbose form of CSC
:
type CSC = CS(compressRows=false);
Poke @lydia-duncan @bradcray and @mppf due to the update in Part 2.
Ah, excellent that 2a works! That's interesting about 2b - my suspicion is that the problem is due to our reliance on the generation of the hidden _new function for classes when a relevant initializer is called and that I probably put some code in to circumvent the generation of that function when the type is fully known (which this example proves I should not have done).
(pinging @noakesmichael so that he is aware of this, too)
I'll add the 2a and 2b variants to our test system.
Note that it does not change the behavior of case 1
1:
test/classes/initializers/generics/typeAlias/errorNewExpr.chpl
declares the failure of this to compile to be
errorNewExpr.typeless.good.
2a, 2b:
I believe #11656 locks in these not working as written. For the
new
expression using the alias to invoke the initializer, the
initializer now needs a type
formal argument with the same name as the
type member.
2b: was test/classes/initializers/generics/typeAlias.chpl
2a: was test/classes/initializers/records/generics/assignment/typeAlias.chpl
type eltType
arg to the initializer.2a-2: fails for the same reason as 2a, before detecting the mismatch.
2c:
This works,
test/classes/ferguson/record-alias-generic-concrete.chpl
test/classes/initializers/compilerGenerated/friendly_generics.chpl
(The latter pending #12693)
3:
Following the example of 2a, I was able to make this work by adding an
explicit type T
argument to A
's initializer,
class B {
var b1: real;
var b2: int;
proc init(v1: real, v2: int) {
b1 = v1;
b2 = v2;
}
}
record A {
type T;
var a: owned T;
proc init(type T, args...) {
this.T = T;
a = new owned T((...args));
}
}
type C = A(B);
var c = new C(99.0, 42);
writeln(c);
writeln(c.a);
writeln(c.T:string); // prints B
writeln(c.a.b1); // prints 99.0
writeln(c.a.b2); // prints 42
It feels a little fragile though. I don't know if this is different enough from the existing generic+alias+initializer tests to add a new one.
Thanks Paul! I need to mentally refresh myself on the issue before determining what the next step is (not sure if I'll get to it right away, but hopefully soon)
I've been trying out some ideas with generic records and classes, and ran into a few issues. I saw #3406 and some of the associated examples, and wanted to see whether the compiler could handle what I was trying to do. I thought filing an issue here might help me document what I'm trying to do.
Part 1: A problem with type aliases of generic types
After looking at this example and experimenting with a few variants, I noticed that the generic type specified by the alias is not actually respected.
The following updated test shows that the constructor argument of "1" is what determines the type of
A.x
, not the type alias:Part 2: Generic containers with type fields
Update 11/8/2017: Added Parts 2a and 2b; updated the old "Part 2" to Part 2c.
Part 2a: Records with explicit initializers
To my surprise, this code works!
With the output:
This
Generic
record even produces errors as expected (unlike Part 1):Produces output:
Part 2b: Classes with explicit initializers
Unfortunately, adapting Part 2a from a
record
toclass
type does not work:Which produces the output:
Part 2c: Records without explicit initializers
Assuming that Part 1 can be resolved, I'm hoping to work with generic types that have a type field. Again comparing to this example, I'm hoping to have something like:
which currently produces the following error message:
Part 3: Forwarding constructor arguments
Ultimately, I want a type alias that concrete-izes a generic record, where the "inner" type is a class, and the constructor arguments to the type alias get forwarded to the class's constructor. I think this would look something like: