Cannot Convert [Int] to [Int] in Generic Implementation

Cannot implicitly convert type 'Int' to 'T'

Any time you find yourself switching on a type in a generic you are almost certainly doing something wrong. Generics should be generic; they should operate identically completely independent of the type.

If T can only be int or string then don't write your code this way at all in the first place. Write two methods, one that returns an int and one that returns a string.

Cannot convert value of type 'Int' to expected argument type 'Int' in generic

func notify<Int>(data: Int, value: Int, at indexPath: IndexPath?) {
buttonSelection.updateTag(tag:value, for:indexPath)
}

This is not how you implement a method that takes Int. That <Int> means you have a generic method with a parameter called Int. It's not the integer type Int but name of the generic parameter, same as <T>:

Sample Image

If you declare a generic method in a protocol you cannot implement just one type, you have to implement all the types.

It's possible you actually want to use a protocol with an associated type and not generics:

protocol NotifyDataSelected: class {
associatedtype T
func notify(data: T, value:T, at indexPath: IndexPath?)
}

extension MainButtons: NotifyDataSelected {
typealias T = Int
func notify(data: Int, value: Int, at indexPath: IndexPath?) {
}
}

Java Generics cannot convert Type in Type

Why is the first one working and the second one isn't?

Because List<ASpecificSubTypeOfTestType> (the return of the first method) is a subtype of List<? extends TestType>, but Pair<String, List<ASpecificSubTypeOfTestType>> (the return of the second method) is not a subtype of Pair<String, List<? extends TestType>>.

Let us change your example from Pair to List, and TestType to Object for a moment:

public class Test {

public static void main( String [] args ) throws Exception {

Collection<?> val = null;

List<?> single = testSingle( val ); // OK

List<List<?>> pair = testList( val ); // ERROR

}

static <T> List<T> testSingle( Collection<T> val ){
return null;
}

static <T> List<List<T>> testList( Collection<T> val ){
return null;
}

}

From a technical point of view, List<SomeSpecificType> is a subtype of List<?>, but List<List<SomeSpecificType>> is not a subtype of List<List<?>>, for the same reason that List<String> is not a subtype of List<Object> -- the type parameters are different concrete types (one is List<SomeSpecificType> and the other is List<?>).

For a more practical reasoning, testList returns a List<List<T>> for some T. We don't know what that T is, but we know that it is some concrete type. And this List<List<T>> that is returned is a list that can only contain List<T>. It cannot contain List<S> if S is not T, because List<S> and List<T> are not subtypes of each other. Even though we don't know what T is, we know that there exists some choice of T, and all the element lists must have that T as the type parameter.

On the other hand, the type you're assigning it to, List<List<?>>, is a list that can contain every type of list at the same time. So you can put in a List<Integer> and a List<String>, etc. at the same time and it would be okay. You can never do that with a List<List<T>>, no matter what you choose T to be.

Therefore, the two types are clearly incompatible.

What can go wrong? With the List<List<?>> reference, you can insert List<Integer> and List<String> into the list. And then with the List<List<T>> reference inside the function, you can extract all the elements as List<T>, which they won't be. So it is unsafe.

You might say, what if I never put things into the List<List<?>> reference? Is that safe? But if that were the case, you should instead use List<? extends List<?>>. The ? extends wildcard makes it a consumer, so you cannot insert anything into it except null; and it also makes the type compatible (List<List<SomeSpecificType>> is a subtype of List<? extends List<?>>).

The moral of the story is, wildcards in deeper parameters do not mean what you think they do.

Unable to assign untyped int to generic struct field

Instantiation must happen at the type level, not on a method level, and methods can't introduce new type parameters, see How to create generic method in Go? (method must have no type parameters)

This means when you want to use R2, you then have to choose type arguments for the type parameters, and the methods can't change those, you're "stuck" with the types you choose on R2's instantiation.

Also note that since the constraint for IDTYPE is comparable, which may be string for example, the integer 123 cannot be assigned to the ID field in all cases because it may have a type of string.

If you want / must handle multiple concrete types for the IDs, generics is not the right choice. Interfaces may be used instead:

type R2 struct {
ID any
IsActive bool
}

Also note that the receiver must be a pointer if you wish to modify the receiver (e.g. fields of a struct).

If you wish to restrict the values stored in ID to comparable, use a (generic) function for it.

Here's how you can do it:

type R2 struct {
ID any
IsActive bool
}

func (r *R2) Store(ctx context.Context) error {
setID(r, 123)
return nil
}

func setID[ID comparable](r *R2, id ID) {
r.ID = id
}

Testing it:

r := &R2{}
var s Storable = r

s.Store(context.TODO())

fmt.Println(r)

Which outputs (try it on the Go Playground):

&{123 false}

This provides flexibility (you can set any comparable values to the ID field using setID()), and provides compile-time safety: attempting to set an incomparable value will result in a compile-time error such as this:

setID(r, []int{1}) // Error: []int does not implement comparable

Value of type 'T' cannot be converted to

Even though it's inside of an if block, the compiler doesn't know that T is string.

Therefore, it doesn't let you cast. (For the same reason that you cannot cast DateTime to string)

You need to cast to object, (which any T can cast to), and from there to string (since object can be cast to string).

For example:

T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;

Why can't I cast an item to a generic type — where the generic type is an interface, and after checking that the item implements said interface?

Here you go:

   if (effect is T typed) {
effects.Add(typed);
}

As for why: you'd need an object cast in the middle: (T)(object)effect



Related Topics



Leave a reply



Submit