-
-
Notifications
You must be signed in to change notification settings - Fork 729
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
Add TrueTypeOf and ToFunctionType to phobos.sys.traits. #10710
Conversation
TrueTypeOf is completely new. It's a wrapper around typeof which bypasses typeof's behavior with @Property and instead gives the actual type of the function. For other symbols, it's the same as typeof with the caveat that template alias parameters cannot accept general expressions. So, TrueTypeOf will work on symbols, but not stuff like &var. But it will work on the symbol for a function or variable, thereby providing a replacement for typeof in situations where property functions need to be treated as the functions that they are. The plan here is that the function-related traits in phobos.sys.traits will operate solely on types (except in situations where the actual symbol is required - e.g. to get the names of parameters), like most traits typically do. std.traits has a number of its function-related traits operate on symbols in part to work around the issue with property functions (as well as stuff like trying to treat variables with opCall as functions instead of requiring that the symbol for opCall itself be passed). TrueTypeOf will therefore allow code to get the actual type of the function and thus we won't need to have as many traits operate on symbols instead of types. That will also have the benefit of reducing the number of cases where traits operate on both types and other symbols, since that has a tendency to be error-prone and make the code harder to understand. It should also help with clarity when a trait doesn't try to handle everything itself. Exactly how this will affect each trait will of course depend on the trait in question, but the idea is to simplify things and ultimately end up with traits which are easier to understand and less error-prone. The other new symbol, ToFunctionType, is a template which converts function types, function pointer types, and delegate types to the corresponding function type. So, something like `int function(string)` or `int delegate(string)` would become `int(string)`. This is primarily useful in implementing other function-related traits, but it also provides a way to get function types to use in is expressions for testing or providing examples. In terms of functionality, ToFunctionType is a replacement for std.traits.FunctionTypeOf. FunctionTypeOf attempts to operate on anything that's "callable" (both types and symbols), which makes it a bit of a mess (and which actually cannot work in some cases due to templated types or functions not having been instantiated). And looking over where it's used in std.traits, it's usually used on types anyway. So, ToFunctionType operates exclusively on types. The change in name is because FunctionTypeOf definitely sounds like a trait that's operating on a symbol to get its type (even if it also accepts types), whereas ToFunctionType sounds much more like it's converting the given type, which is what it's doing.
Thanks for your pull request, @jmdavis! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + phobos#10710" |
BTW, the assertion with |
While |
As they're clearly completely unrelated, I see no issue. |
Is If it really needs to exist, its name should be something more descriptive, like |
Yes, it's necessary, because what Given that we're clearly not going to get rid of optional parens (as was originally the plan with
If the language feature does the wrong thing, and we can't fix the language feature, the library needs to have an alternate solution. And when it comes to features related to type introspection, it's highly unlikely that we will ever be able to fix them, because it would break a lot of code in unpredictable ways if we tried - especially with how much D's type introspection is built on checking whether a particular piece of code compiles or not.
Maybe? I would have thought that |
Well, are the workarounds really necessary? My impression was that a lot of these workarounds are the result of generality creep, and that we could do away with them by being stricter about what kinds of inputs we accept. Since you're working on this directly, though, I'm willing to defer to your judgement here.
I'm fine with this as long as the alternate library solution has a clearly distinct name. E.g., having IMO, the name
I'll grant that The name |
If any trait deals with property functions as symbols, and it needs to get the type of a symbol, then it has to deal with the fact that From what I can see, the best way to clean this up for most traits is to make it so that they only operate on types and not on both types and symbols which aren't types. That way, what
So,
Well, I disagree. If it were
I thought about names along those lines, but that's long and ugly for a trait that's likely to be used extensively. Honestly, even just writing the tests, I find
Except that in the general case, if you're getting the type of a symbol rather than an expression, it is preferable to use I expect that the only reason that we don't get more bugs due to
Honestly, if it weren't the case that fixing |
In my experience, when For example, in Lines 1377 to 1378 in b57f75d
A similar workaround is used in Lines 1025 to 1026 in b57f75d
And in phobos/std/format/internal/write.d Lines 1896 to 1899 in b57f75d
So when you say things like this:
...I think you are simply incorrect. In this case, the programmer almost certainly wants the result to be |
Well, this factors into a related problem that I decided needed a trait when I was working on this but haven't sat down to actually work on yet, so I haven't yet thought about naming it. And maybe I should have sat down and worked through that before creating this PR, but I was almost done with this and several other traits and decided to wait until afterward, since the amount of code was piling up. The problem relates to property functions in that optional parens cause problems with type introspection. It means that you could have something like If So, if you want to know the type of the symbol for Arguably, a part of the problem here is that Right now, to consistently get the type of the symbol when used in an expression, you need to do something like declare a lambda which returns So, we need a trait where you say that you want the type of As things stand, So, I'll rename |
Actually, I'm just going to close this PR and do another one with |
TrueTypeOf is completely new. It's a wrapper around typeof which bypasses typeof's behavior with
@property
and instead gives the actual type of the function. For other symbols, it's the same as typeof with the caveat that template alias parameters cannot accept general expressions. So, TrueTypeOf will work on symbols, but not stuff like &var. But it will work ion the symbol for a function or variable, thereby providing a replacement for typeof in situations where property functions need to be treated as the functions that they are.The plan here is that the function-related traits in phobos.sys.traits will operate solely on types (except in situations where the actual symbol is required - e.g. to get the names of parameters), like most traits typically do. std.traits has a number of its function-related traits operate on symbols in part to work around the issue with property functions (as well as stuff like trying to treat variables with opCall as functions instead of requiring that the symbol for opCall itself be passed). TrueTypeOf will therefore allow code to get the actual type of the function and thus we won't need to have as many traits operate on symbols instead of types. That will also have the benefit of reducing the number of cases where traits operate on both types and other symbols, since that has a tendency to be error-prone and make the code harder to understand. It should also help with clarity when a trait doesn't try to handle everything itself.
Exactly how this will affect each trait will of course depend on the trait in question, but the idea is to simplify things and ultimately end up with traits which are easier to understand and less error-prone.
The other new symbol, ToFunctionType, is a template which converts function types, function pointer types, and delegate types to the corresponding function type. So, something like
int function(string)
orint delegate(string)
would becomeint(string)
. This is primarily useful in implementing other function-related traits, but it also provides a way to get function types to use in is expressions for testing or providing examples.In terms of functionality, ToFunctionType is a replacement for std.traits.FunctionTypeOf. FunctionTypeOf attempts to operate on anything that's "callable" (both types and symbols), which makes it a bit of a mess (and which actually cannot work in some cases due to templated types or functions not having been instantiated). And looking over where it's used in std.traits, it's usually used on types anyway.
So, ToFunctionType operates exclusively on types. The change in name is because FunctionTypeOf definitely sounds like a trait that's operating on a symbol to get its type (even if it also accepts types), whereas ToFunctionType sounds much more like it's converting the given type, which is what it's doing.