Replies: 39 comments
-
Could it solve #662 problem? So, would it possible to write code like this? public void GenericMethod<T>(T obj)
{
if (obj is struct s)
{
OptimizedForStructs(s);
// compiler CERTAINLY KNOWS that s is struct
// so it's certainly safe to invoke method with "struct" type constraint
}
}
private void OptimizedForStructs<T>(T obj) where T : struct
{
// optimized for value types code
} |
Beta Was this translation helpful? Give feedback.
-
@Opiumtm How would you imagine that would be translated into IL? Or into machine code? |
Beta Was this translation helpful? Give feedback.
-
@gafter It's about "more restrictive" generic type argument of Runtime would throw exception (on generic type argument check) if this method is invoked with object instance of reference type, but it would be never invoked with reference type instance, thanks to |
Beta Was this translation helpful? Give feedback.
-
@gafter |
Beta Was this translation helpful? Give feedback.
-
@Opiumtm We can't do it at compile-time because the compiler doesn't know what specific struct type the value will end up being at runtime. That will only be known at runtime. |
Beta Was this translation helpful? Give feedback.
-
@gafter
|
Beta Was this translation helpful? Give feedback.
-
No, given the new language construct proposed here, knowing that it is a value type no longer implies knowing what that value type is. The compiler could generate a constrained call. But what value type should the compiler place into that constrained call? |
Beta Was this translation helpful? Give feedback.
-
@gafter |
Beta Was this translation helpful? Give feedback.
-
The exact type is definitely known by the compiler, the part that is unknown is the instance of the type which is only known at run-time so how do you expect the compiler to verify that when it doesn't even know what |
Beta Was this translation helpful? Give feedback.
-
@eyalsk No, in the (proposed) code static void M(object o)
{
if (o is struct s) M(s);
} where public static void M<T>(T s) where T : struct {} The exact static type that is being passed to |
Beta Was this translation helpful? Give feedback.
-
@gafter Okay, might be poor wording on my part but I really don't understand you because the compiler definitely knows what the non-generic M expects and this is what I was referring to, now, the part that isn't known is where Basically, what I'm trying to say is that the following part |
Beta Was this translation helpful? Give feedback.
-
In order to emit the invocation, the compiler needs to know the type. |
Beta Was this translation helpful? Give feedback.
-
@gafter |
Beta Was this translation helpful? Give feedback.
-
@Opiumtm But you still need to pass the type argument at the call site. |
Beta Was this translation helpful? Give feedback.
-
@eyalsk private void OptimizedForStructs<T>(T obj) where T : struct What's problem to pass |
Beta Was this translation helpful? Give feedback.
-
I don't get this proposal. Why is this use case so important that it should be elevated to the level of language syntax? How often are people actually writing this type of code? And even if you were writing this kind of code every single day, what's wrong with just using helper methods? And why is this little slice of reflection more deserving of new syntax than all the other use cases of reflection? I wish the community would push back a little harder on all of the "I occasionally do this thing so lets make a dedicated syntax for it" type requests. |
Beta Was this translation helpful? Give feedback.
-
When the issue gets to this point I tend to agree, but there's nothing wrong with putting stuff out there to see if it's something everyone is interested in. |
Beta Was this translation helpful? Give feedback.
-
I can see some use cases for stuff like generic specialization within a method but I might approach it differently and I honestly don't know how often it would be that useful. 🍝 Looking at @Opiumtm 's specific scenario maybe some syntax like this? public void GenericMethod<T>(T obj)
{
if (T is struct)
{
OptimizedForStructs(s);
// compiler CERTAINLY KNOWS that T is a struct
}
}
private void OptimizedForStructs<T>(T obj) where T : struct
{
// optimized for value types code
} The difference being the application of the Another example: public int Count<T, TE>(T enumerable) where T : IEnumerable<TE> {
if (T is IList<TE>) return enumerable.Count;
// do other count here
} |
Beta Was this translation helpful? Give feedback.
-
@HaloFour Agreed (more examples). |
Beta Was this translation helpful? Give feedback.
-
@MgSam But is it really occasionally? many frameworks use reflection all the time.. testing frameworks, DI frameworks, UI frameworks and whatnot, if the language can make reflection better then why not? C++ committee make the experience for templates better all the time.. does every C++ programmer create templates? well, I guess they are trying to make it easier but still, I know it's really comparing apples and oranges but the point is a language feature not always have to lean towards the majority... p.s. I really see this more of a new pattern than actually a new syntax to the language. |
Beta Was this translation helpful? Give feedback.
-
@eyalsk Exactly my point. This proposal covers what, 1% of reflection use cases? To cover them all would be a mammoth undertaking. And for what benefit? It's not like it gives you any additional compile time benefits (as I write C# code generators reasonably frequently- the only one of these use cases I've ever actually done myself was check a type for an attribute. But it's simple enough to do with a helper method. And most developers never write that sort of code. |
Beta Was this translation helpful? Give feedback.
-
@MgSam Okay, I see your point and I tend to agree. |
Beta Was this translation helpful? Give feedback.
-
Because the language team doesn't want to promote reflection by giving it an easy syntax. |
Beta Was this translation helpful? Give feedback.
-
I don't think we should state what they want or think before having an official words on it and until then speak for ourselves. Besides, if they didn't want to discuss this then why @gafter bothered to copy/paste it to this repo? he could have just closed it. In my opinion the proposal isn't bad and like I wrote before to me it's more of a pattern than a syntax, it does make things more readable, however, it's very niche and like @MgSam wrote it covers only tiny bit of reflection use cases, still, it might have some value. |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
@Joe4evr Fair enough but still, does this mean we shouldn't discuss the idea? :) |
Beta Was this translation helpful? Give feedback.
-
The common runtime patterns for class/struct are: if (T is struct) if (default(T) != null) And if (T is class) if (default(T) == null) Nullable; is more tricky :) |
Beta Was this translation helpful? Give feedback.
-
48 occurrences of |
Beta Was this translation helpful? Give feedback.
-
Related but more limited in scope "Pattern match via generic constraint" #905 |
Beta Was this translation helpful? Give feedback.
-
With the new list pattern syntax using |
Beta Was this translation helpful? Give feedback.
-
@Unknown6656 commented on Sun Jun 26 2016
I would like to propose more "pseudo-types" for the
is
-operator, as I (and many other developers) often work with reflection andSystem::Type
and have wondered, whether one could optimize code readabilty in such situations.As you can probably see, I would like to see different keywords/accessors/etc. being used with the
is
-operator, instead of using the circumbendibus syntax with withSystem::Type
:This proposal has multiple advantages:
System::Type
-instances(Especially for attribute and generic checks)
One could propose the following syntax rules for the
is
-Operator:NOTE: The expression
bool test = obj is <,,>
would match any object instanceobj
, whoms type is a generic type with exactly three generic type arguments.@HaloFour commented on Sun Jun 26 2016
What happens in the case that
obj
isnull
? Do all of the above tests then fail?Also, neither
obj is abstract
orobj is interface
make much sense. The implementation ofobj
can't be either. Do you mean to test ifobj
happens to have an abstract base class, or ifobj
happens to implement any interface? What possible use case could that have?Speaking of use cases, when would it use useful to know that
obj
happens to be a generic class of some specific arity? What can you do with that information?@Unknown6656 commented on Tue Jun 28 2016
@HaloFour: Well, you are right, that
... is interface
or... is abstract
do not make sense...+It would be better to implement something like this to test for multiple interfaces:
Concerning your
null
-question: The result should always befalse
(as theis
-comparator would return in previous C# versions)Concerning your last question, whether it would be useful: I have often used generic type creation or generic type pattern matching in the past, and I think that it could be rather useful.
One could also use this feature inside various .dotnet projects (e.g. various compilers or analysers which require pattern matching/analyzation)...
@bondsbw commented on Fri Jul 01 2016
While we're at it, perhaps comparisons directly on the type would also be useful:
@bondsbw commented on Fri Jul 01 2016
Though now that I think about it, the syntax
T : class
might be more appropriate given similar usage for type parameters constraints. I don't know.@Unknown6656 commented on Sat Jul 09 2016
@bondsbw: Your last proposal could be an issue for readability in the following situation:
is identical to:
I think that using a colon (
:
) instead ofis
renders the code less readable (independent of bracket-usage)@bondsbw commented on Sat Jul 09 2016
Good point. I can't think of a reason to prefer the colon syntax which justifies the confusion caused by what you wrote.
Beta Was this translation helpful? Give feedback.
All reactions