Replies: 10 comments
-
I really like this approach, it appears quite elegant. Although it would necessitate separate declaration of such an interface, which could be viewed as an inconvenience, I think it provides the desired expressiveness. It also avoids the common problem that inline, point-of-use declaration of intersection types is often very ugly in languages like TypeScript and Scala. Since interfaces can be declared as public and nested in classes an approach to the generic constraint situation might look like public static class Extensions
{
public implicit interface ICombined<T>: IComparable<T>, IEquatable<T> {}
public static ISortetSet<T> ToSortedSet<T>(this IEnumerable<T> source)
where T: ICombined<T> { ... }
} Note that the interface above is a shallow intersection which, while perhaps not the most theoretically sound, is highly practical in this case. |
Beta Was this translation helpful? Give feedback.
-
@gafter I think when you say
You mean an object of both types |
Beta Was this translation helpful? Give feedback.
-
Isn't this just type-classes in disguise?
…On Sat, Mar 25, 2017 at 01:12 Aluan Haddad ***@***.***> wrote:
@gafter <https://github.com/gafter> I think when you say
create a property on an object into which you can place an object of *either
type*
You mean an object of *both types*
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<https://github.com/dotnet/csharplang/issues/344#issuecomment-289177340>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AB5kk559_SrTVdn02Uqmgnzu7a6VX6rDks5rpGoHgaJpZM4Mo4kU>
.
|
Beta Was this translation helpful? Give feedback.
-
I prefer (#619)
|
Beta Was this translation helpful? Give feedback.
-
@weitzhandler that's an interesting approach, but the main issue I see with it is that using statements like that are only scoped to the code file. Once compiled, you lose the definition. Having a CLR-defined type retains the definition. |
Beta Was this translation helpful? Give feedback.
-
@weitzhandler while I'm not a huge fan of the type alias syntax, I could certainly live with it. This is about the ability to express something in the type system and I would say #619 describes the same use case. |
Beta Was this translation helpful? Give feedback.
-
I just leave this comment to track the issue |
Beta Was this translation helpful? Give feedback.
-
@Thaina. |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt By Tracking I mean search for |
Beta Was this translation helpful? Give feedback.
-
This is not going to work well in the interpreter. how do you implement a reference to an |
Beta Was this translation helpful? Give feedback.
-
@gregsdennis commented on Tue Apr 21 2015
The Problem
Define an interface in such a way that its entire purpose is to represent a set of other interfaces.Suppose you have two interfaces:
Now suppose you want to create a property on an object into which you can place an object of either type. Since they have no common ancestry, you would have three options (that I've seen, you may devise your own):
object
and then test/cast in order to access the functionalityIA
andIB
, we useIComparable
andIConvertible
?This only works for classes which specifically implement the
ICombined
interface. You would not be able to assign types likeint
,double
, andstring
, each of which implement bothIComparable
andIConvertible
.The Solution
We introduce a new usage of theimplicit
keyword for interfaces.IComparable
andIConvertible
can be interpreted as implementingICombined
.The remainder of the code could stay the same, but now, in addition to explicit implementations of
ICombined
we could also assign any type which implements bothIComparable
andIConvertible
, includingint
,double
, andstring
.Additionally, you could use this new interface to define a collection of such objects:
Defining an interface this way, it becomes retroactive. That is, types which implement all base interfaces for the implicit interface also are said to implement the implicit one.
The Rules
Finally, the run-time will have to do some type checking, which it should do already for the
is
andas
keywords. It wouldn't need to know all implicit interfaces that a type implements, it would just need to check as requested.This basically asks, "Does the type of
6
, which isint
, implementICombined
?" To determine that, it sees thatICombined
is an implicit interface so it asks, "Does it implement all of the interfaces implmented byICombined
?" So it's equivalent to writing:Simple field and property assignments would be compiler-verifiable.
@HaloFour commented on Tue Apr 21 2015
The compiler might be able to sneakily handle that within the code that it compiled itself but it couldn't affect how other assemblies might treat that type. To make the CLR recognize
int
as anICombined
would require changes to the runtime.You might want to submit this as a feature request to the CoreCLR team.
@dsaf commented on Wed Apr 22 2015
Is it related to intersection types?
@gregsdennis commented on Wed Apr 22 2015
@dsaf, not really, but I can see the proximity to that idea.
The concept behind this is closer to type verification by implementation. I remember reading about a feature that some languages have where the class is defined not by some concrete Type concept, but rather by the functionality that the class provides. By this, a class can be considered to implement an interface simply by implementing the contract it states (whereas C# requires you to explicitly state you're implementing the interface, even if the contract happens to match some other interface).
This could considered be a partial implementation of that feature, but still keeping to the ideals which already exist in C#.
@gregsdennis commented on Wed Apr 22 2015
@HaloFour, I was going to say that the CLR wouldn't have to change, citing that
could be converted by the compiler into
before translating to IL.
However, now that I think about it further, it would still need to have a type for any variable which holds an
ICombined
value. Otherwise, it would have to useobject
and inject a lot of casts to switch between the various interfaces when it needs to process the value. That could lead to other issues.Regarding use in other assemblies, those assemblies would have to reference this one to get the type definition of
ICombined
. How would this be a problem for those assemblies?@HaloFour commented on Wed Apr 22 2015
You could handle this via a helper method that does some reflection (obviously caching the results). I actually had some incubator project some years back to provide a duck-typing helper method that would construct a concrete proxy class in a dynamic assembly that would implement the interface members and point them to compatible members of the target type. It worked nice but it had the same issues where the proxy type isn't the same as the target type and you can't convert between them. The compiler would have the same issue. If it emitted a synthetic type the instance is no longer the original type. You couldn't pass that
ICombined
to another method and cast it to anint
.@bondsbw commented on Wed Apr 22 2015
@gregsdennis
In that case it might make more sense to remove the braces:
@gafter commented on Fri Nov 20 2015
I wonder if intersection types would be a better fit, since there is little reason to give a name to the combination.
@benaadams commented on Sat Nov 28 2015
Have lots of these types in https://github.com/dotnet/coreclr/issues/2179 that require naming for ease of use.
@Thaina commented on Wed Mar 09 2016
I would prefer that we could alias and cast or check for a group of type than making new implicit interface
For solving your problem it would better if we just
Syntax is
(type,type)
or maybe(type & type)
and(type | type)
But it would require CLR support
@gregsdennis commented on Wed Mar 09 2016
@Thaina, I think your idea is good. I like the idea of declaring the shorthand in the using statement.
I think the
(type | type)
syntax would explain the concept better in code. It is literally "this or that type."@HaloFour commented on Wed Mar 09 2016
The
(A, B)
syntax is proposed for tuples. I like(A & B)
since the intersected type would have to implement both interfaces. The concept of(A | B)
is interesting, a type that implements either interface and the consumer can only access shared members. Java does have limited typing like this in exception handlers, e.g.catch (IOException | SQLException exception) { }
.I wonder how much of either concept that the compiler could implement without CLRsupport. There are tricks that the compiler could do within a method, but it would have to be pretty limited.
@gregsdennis commented on Wed Mar 09 2016
@HaloFour, you are correct: the desired syntax for this should be
(A & B)
. (Early morning; brain not booted.)@aluanhaddad commented on Thu May 12 2016
Intersection types would add a great deal of expressiveness to the language. I really want to see this implemented and I'm really happy to see renewed interest. This would allow for much more powerful and expressive consumption of generic APIs and allow for powerful, typesafe ad hoc cross axial classification of types. I think the
&
syntax is a good choice and has worked out very well in languages like TypeScript.As for the question of declaring a name for some intersection type, I think the
using
syntax would provide that intuitively.@Thaina commented on Sun Jun 05 2016
I have seen many proposal about intersect/union type at
where
clause. And I think it all could be relate totrait
tooShould we have some thread or tag to sum up all these kind of proposal as
generic enhancement
ortype constraint
?@aluanhaddad commented on Fri Jun 24 2016
@Thaina the problem is that while
works very well already for specifying intersecting type constraints, it is impossible to call such a method (with resorting to dynamic) without casting to a type implementing both interfaces. Such a definition may not be available, and if it is it is still not ideal. I would welcome a thread gathering ideas for these proposals, but it is about much more than specifying generic constraints.
Basically,
Union Types would be very useful in generic constraints.
Intersection types would be very useful for consuming generic methods and for pattern matching.
Beta Was this translation helpful? Give feedback.
All reactions