chapel-lang / chapel

a Productive Parallel Programming Language
https://chapel-lang.org
Other
1.77k stars 416 forks source link

Wrapper classes around Primitive Types #13007

Open LouisJenkinsCS opened 5 years ago

LouisJenkinsCS commented 5 years ago

I would like to request that Chapel support primitive wrappers, similar to Java. Java provided wrappers such as Integer that wrap an int, a Float that wraps float, etc. I believe that Chapel should do something similar, especially now given that lifetime management in conjunction with delete-free programming can allow such things to be 'garbage collected' in a way that makes the issue of memory management more of a moot point. I would recommend though, that these primitive wrappers be parameterized, similar to their primitive counterparts.

class Integer {
   param bitSize : int;
   var _value : int(bitSize);
   forwarding _value;
}

As well I'd like for primitives to be implicitly convertible between primitives and their primitive wrappers, similar to how they are in Java. As well that operators be defined over the primitive wrappers, since forwarding currently does not forward operators. Finally, I would like to request that they be interoperable with C code, so that you can easily cast to and from c_int, etc.

One example where something like this can come in handy would be handling things that return things where the type is determined at runtime, such as getsocketopt and setsocketopt. In particular lets abstract this to a function f calls out to some C function that returns a c_void_ptr, but we that the type of the output is determined by its input (similar to the *socketopt pair mentioned above). To enable a more 'chapel-tastic' way of writing this code, imagine if f returned some kind of owned object.

proc f(x) : owned object { /* ... */ }

var ret = f(x);
if ret : Integer(64) then /* ... */;
else if ret : Real(64) then /* ... */;
else if ret : string then /* ... */;
/* ... */

Of course in reality we already know the actual return type.

proc f(x) : owned object { 
   select (x) {
      when x == 1: return new owned Integer(1);
      when x == 2: return new owned Real(1.0);
      when x == 3: return new owned string("1");
   }
}

var ret = f(2) : Real;

Any objections?

mppf commented 5 years ago

While I don't object to such types existing somewhere, I think it'd be better (as a language design matter) to express this pattern using "interfaces" that contain a runtime-type. https://github.com/chapel-lang/chapel/blob/master/doc/rst/developer/chips/2.rst#the-any-type

Since we expect that interfaces/constrained generics will apply to int as well as records, strings, classes, and anything else, this elegantly solves the problem.

Of course that relies on language work that is not yet completed. I'm trying to discuss here this proposal as a language design direction (rather than as something you might you in a library/prototype/etc).

For getsocketopt specifically, I think the API design is cleaner if there are different methods with different return types. We discussed implementing one getsocketopt that varied the return type at compile-time and decided that was not as nice as separate methods. See https://github.com/chapel-lang/chapel/issues/12356