Copy initialization: how has it changed?

The following excerpt, coming directly from Chapel's documentation
(Records — Chapel Documentation 2.4), does not compile (any more?):

record MyString {
  var s : string;
}

// normal copy initializer
proc MyString.init=(other: MyString) {
  this.s = other.s;
  writeln("normal init=");
}

// initialize from a string
proc MyString.init=(other: string) {
  this.s = other;
  writeln("string init=");
}

var A = new MyString("hello");
var B = A; // "normal init="
var C : MyString = "goodbye"; // "string init="

and the error issued by the compiler in version 2.4 is

advanced.chpl:19: error: a cast creating 'MyString' from 'string' is missing
advanced.chpl:12: note: expected because init= is defined here between these two types

What is the correct form of doing this now? Thanks for any help,

Nelson

Hi Nelson —

Oops, that's embarrassing. At some point we decided that if a copy
initializer is supported between types then a cast between those
types should be required as well, which is what the error:

code.chpl:19: error: a cast creating 'MyString' from 'string' is missing
code.chpl:12: note: expected because init= is defined here between these two types

is conveying.

The fix is to add a cast operator, for example like this:

operator :(x: string, type t: MyString) {
  var s: MyString = x;
  return s;
}

which should make things work again
(Run – Attempt This Online).

If you have the time and interest, would you mind opening a GitHub issue
against this error? We should (a) fix the test case, (b) update the
description, and (c) make this code in the spec testable to prevent it
from breaking again in the future.

Thanks,
-Brad

Hi Brad: within my serious limitations with github :slight_smile: , and a little help from google, I opened an issue --- I hope I did it more or less correctly. Thanks for the prompt response! Meanwhile, adding the cast to the code made the compilation work. Since I did not include any explicit cast in the code, however, I don't really know why it works now.

Regards

Nelson

Perhaps the need to define a cast operator can be traced back to this text in the documentation:

"If a user implements their own init= method, they must also implement an assignment operator for the same record type. Implementing one without the other will cause the compiler to issue an error. Rationale: this requirement exists to mitigate hard-to-debug problems by requiring that type authors take responsibility for both init= and = implementations, or neither implementation."

Perhaps at some point, the requirement to implement an operator = was replaced by the requirement to implement an operator : ?

The answer to this is that the failure was due to a check in our
compiler rather than the code necessarily relying on the operator
itself. We do that check to ensure that types behave in a consistent
manner - it helps avoid cases where a library designer failed to test
behavior in that particular way of getting a new instance, leading to
their assumptions being violated and potentially bad behavior in other
areas of their code for their users.

Lydia

Yes Lydia; the compiler error message makes more sense to me now.

Thanks

Nelson

@nelsonluisdias — To build on Lydia's response, here's a rationale that I'm proposing adding in Make spec's docs of `init=` on records testable and refresh them so they work again by bradcray · Pull Request #27251 · chapel-lang/chapel · GitHub to address the issue (both making the examples work again, and documenting and rationalizing the requirement:

Supporting a mixed-type copy initializer provides a way
to convert an expression of one type (T1) into another (T2)
using forms like: var myT1: T1 = myT2;. The other common way of
converting types in this way is to use a cast, like myT2: T1, so
Chapel requires both operations as a means of ensuring the type author
makes both forms available.

Thanks again for bringing this to our attention and filing the issue,
-Brad

Hi @bradcray: I understand the rationale now. Thanks to everybody for the
explanations.

Regards

Nelson