What's the Difference Between Using or Not Using the 'Where' Clause with Generics

What's the difference between using or not using the 'where' clause with generics?

This is clearly stated in the Swift guide:

The requirements in a generic where clause specify that a type
parameter inherits from a class or conforms to a protocol or protocol
composition. Although the generic where clause provides syntactic
sugar for expressing simple constraints on type parameters (for
instance, <T: Comparable> is equivalent to <T> where T: Comparable and
so on), you can use it to provide more complex constraints on type
parameters and their associated types. For instance, you can constrain
the associated types of type parameters to conform to protocols. For
example, <S: Sequence> where S.Iterator.Element: Equatable specifies
that S conforms to the Sequence protocol and that the associated type
S.Iterator.Element conforms to the Equatable protocol. This constraint
ensures that each element of the sequence is equatable.

Simply put, where lets you specify constraints about the associated types of a generic parameter, while in <> you can't do this.

Is there a practical difference between a type constraint on a generic type directly vs using a 'where' clause?

There is no difference. The first form

func testX<T>(value: T) where T: StringProtocol

was introduced with SE-0081 Move where clause to end of declaration to increase readability, in particular for longer lists of constraints. The rationale was to remove the where clause out of the generic parameter list, for example

func foo<S: Sequence where S.Element == Int>(seq: S)

became

func foo<S: Sequence>(seq: S) where S.Element == Int

in Swift 3. As a side-effect, even simple constraints such as
your T: StringProtocol can be moved to the newly introduced where-clause.

Why are where clauses only valid on functions with generic parameters?

Because ValueType has nothing to do with this method (in the first example). It would be wrong to put such a method in a type (class/struct/enum), since it's not really a true member of that type. It's conditionally a member of that type, depending on the truth value of the where clause.

To achieve this, you would want to put this method in an extension of your type, with the where clause you want. E.g.

extension YourType where ValueType == [String: Any] {
func version() throws -> String { ... }
}

Where clause in generic method

public static Expression<Func<BType, bool>> CastFunc<BType,IType>(Expression<Func<IType, bool>> customWhereClause) where BType : IType

Documentation "Constraints on Type Parameters": http://msdn.microsoft.com/en-us/library/d5x73970.aspx

Java generics vs C# where keyword

This is a very good article.

http://www.jprl.com/Blog/archive/development/2007/Aug-31.html

From that source

Java type and method constraints are specified using a "mini
expression language" within the '<' and '>' declaring the generic type
parameters. For each type parameter that has constraints, the syntax
is:

TypeParameter ListOfConstraints 

Where ListOfConstraints is a '&'-separated list of one of the
following constraints:

  • Specifying a base class or implemented interface on the Generic
    Type Argument by using: extends BaseOrInterfaceType

('&' must be used instead of ',' because ',' separates each generic
type parameter.)

C# generics: using class generic in where clause of method generic

Actually it is possible. This code compiles and runs just fine:

public class A<T>
{
public void Act<U>() where U : T
{
Console.Write("a");
}
}

static void Main(string[] args)
{
A<IEnumerable> a = new A<IEnumerable>();
a.Act<List<int>>();
}

What is not possible is using covariance / contravariance in generics, as explained here:

IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;


Related Topics



Leave a reply



Submit