Skip to content
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

Figure out the right relationship between casts and “constructor calls” #525

Closed
tangent-vector opened this issue Apr 22, 2018 · 2 comments
Assignees
Labels
goal:forward looking Feature needed at a later date, not connected to a specific use case. kind:question questions or discussions

Comments

@tangent-vector
Copy link
Contributor

At the moment, Slang takes cast syntax like this:

int i = ...;
float f = (float) i;

and treats it equivalently to a “constructor call” like:

float f = float(i);

This then turns into a search for an initializer (think “constructor”) in the type float that can be applied to an int argument. That’s all we’ll and good, to make the two equivalent.

A similar thing happens of code needs implicit conversion:

float f = i;

In that case the compiler sees that the user wants a float and starts looking for initializers. The main differences from the explicit case are:

  1. If the expression being converted already has the desired type, we don’t do anything.

  2. If a usable initializer is found, but it isn’t registered as suitable for use in implicit conversion, an error is diagnosed.

Item (2) is maybe obvious, since more conversions should be allowed explicitly than implicitly. Item (1) is important, because we don’t have that rule in the explicit case, so code like the following would be an error by default:

SomeStruct s;
SomeStruct t = SomeStruct(s);

Because we treat casts and “constructor calls” the same, this is true even when cast syntax is used. We work around this for builtin types for now by adding initializers to each type that take an argument of the same type. This is a bit silly, and doesn’t seem like something healthy to impose on user-defined types.

(Aside: no, we aren’t going to go down the C++ “copy constructor” route. Copying a value should be a trivial operation under compiler control, not a chance to run arbitrary user-defined code)

It would be good to eliminate these dummy initializers, but there is also HLSL code out that that contains unnecessary casts (casting a value to the type it already has).

One approach to fix this would be to treat a cast (float) x as similar to the implicit conversion case, including item (1) above, but not item (2). This would handle “identity” conversions without needing explicit initializer declarations.

The place where if gets weird is: should we apply the same logic to float(x) so that “identity” cases become a no-op? If we say “yes” then casts and “constructor” syntax are consistent, but we’d have to special-case single-argument call expressions in a way that isn’t consistent with other calls. If we say “no” then call syntax is consistent, but there is now a difference between casts and “constructor” calls.

I honestly don’t know which of the two options to prefer.

@natduca
Copy link

natduca commented Dec 6, 2023

Putting in Q3 with language polish topics

@swoods-nv swoods-nv added the goal:forward looking Feature needed at a later date, not connected to a specific use case. label Feb 22, 2024
@bmillsNV bmillsNV assigned bmillsNV and kaizhangNV and unassigned bmillsNV Oct 31, 2024
@bmillsNV
Copy link
Collaborator

Closing this was fixed with a const folding change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
goal:forward looking Feature needed at a later date, not connected to a specific use case. kind:question questions or discussions
Projects
None yet
Development

No branches or pull requests

6 participants