Pass Type to Generic Function and Compare

Pass type to generic function and compare

You should check if it's T:

if list[i] is T {
...
}

C# passing a compare class as a generic type

I suggest treating IComparer<T> as a dependence and pass it to constructor; something like this:

  // You can create a heap of any type, right? 
// But in some cases (e.g. Heap<Button>) you should provide a comparer:
// how to compare Button instances
public class Heap<T> {
//TODO: implement here Heap as well as Unheap method having IComparer<T> m_Comparer
...
private IComparer<T> m_Comparer;

// comparer = null - if comparer is not provided, try to use default one
// if it's possible (e.g. in case of Heap<double>)
public Heap(IComparer<T> comparer = null): base() {
// Do we have a default comparer (e.g. for int, double, string)?
if (null == comparer)
if (typeof(IComparable).IsAssignableFrom(typeof(T)) ||
typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
comparer = Comparer<T>.Default;

if (null == comparer)
throw new ArgumentNullException("comparer", string.Format(
"There's no default comparer for {0} class, you should provide it explicitly.",
typeof(T).Name));

m_Comparer = comparer;
}
...
}

So you can create heaps

  // heap of integers, default comparer
Heap<int> heap1 = new Heap<int>();

// heap of integers, custom comparer (via lambda)
Heap<int> heap2 = new Heap<int>(Comparer<int>.Create((x, y) => -x.CompareTo(y)));

// heap of Buttons, custome comparer
Heap<Button> heap3 = new Heap<Button>(Comparer<Button>.Create((x, y) => ...));

And this will throw exception: no default comparer for Button class

  Heap<Button> heapErr = new Heap<Button>();

How to pass a type to generic method in Kotlin?

Here's a complete example:

import kotlin.reflect.KClass

data class User(val name: String)
data class Student(val name: String)

fun getUsers(): List<User> = listOf(User("JB"))
fun getStudents(): List<Student> = listOf(Student("Claire"))

fun <T: Any> getData(clazz: KClass<T>): List<T>? {
return when(clazz) {
User::class -> getUsers() as List<T>
Student::class -> getStudents() as List<T>
else -> null
}
}

fun main(args: Array<String>) {
val types = listOf(User::class, Student::class)
types.forEach { type ->
val data = getData(type)
println(data)
}
}

Passing a generic type to a function in typescript

In order for you to be able to access arg.foo, the compiler must be convinced that, at the bare minimum, arg might actually have a property named foo. So the type of arg must be assignable to something like {foo?: unknown}, where foo is an optional property and the type of the property is the unknown type.

It's not clear from your example if you want to make something stricter than this (say that it definitely has a property named foo, or that the value at that property must be a string). For now, I'm only going to assume that you want to access arg.foo without an error.

If you are using the generic type parameter T as the type of arg, then T must be constrained to something assignable to {foo?: unknown}.

For example:

function a<T extends { foo?: unknown }>() {
function b(arg: T) {
return arg.foo; // okay, no error
}
return b;
}

This saves you from having to write T extends A | B | C | ..., assuming that all of the A, B, C, etc... types are themselves assignable to { foo?: unknown }. Your given A and B types are assignable, so the following works:

a<A>();
a<B>();

Do note that your A and B types from the example are actually identical. TypeScript's type system is structural. Because types A and B have the same structure, they are the same type. It doesn't matter that there are two declarations and two different names:

let aVal: A = { foo: "a" };
let bVal: B = { foo: "b" };
aVal = bVal; // okay
bVal = aVal; // okay

So writing T extends A would be fine if you want the compiler to enforce that foo exists and is a string; it wouldn't stop B from working. A structural type system frees you from having to anticipate all possible named types:

function a2<T extends A>() {
function b(arg: T) {
return arg.foo.toUpperCase();
}
return b;
}

a2<A>(); // okay
a2<B>(); // okay

interface C {
foo: string;
bar: number;
}
a2<C>(); // okay

a2<Date>(); // error
// ~~~~
// Property 'foo' is missing in type 'Date' but required in type 'A'.

If you care about "hardcoding" the name A, you can use an anonymous type like {foo: string} as in T extends {foo: string}, but that doesn't really change much from the type system's perspective, since A and {foo: string} are the same type.

Playground link to code

Pass Type As Variable And Then Compare To Objects Type

On the basis that the type to compare to is known at compile time:

CompareObjectType(typeof(string));

Then you should make your method generic:

bool CompareObjectType<T>()
{
object lComObject = "this is a string";
return lComObject is T;
}

And call like so:

CompareObjectType<string>();

If the type is only known at runtime, you would need to check the type of lComObject at runtime also using GetType().

To emulate is-like behaviour, you could use Type.IsAssignableFrom():

bool CompareObjectType(Type type_variable)
{
object lComObject = "this is a string";
return type_variable.IsAssignableFrom(lComObject.GetType());
}

And call like this:

CompareObjectType(someOtherObject.GetType());
CompareObjectType(typeof(string));

Compare generic types from a collection to the same type java

but if I type <E extends Comparable> in my Box.count method then i cant pass the arguments.

The reason why you can't pass the arguments is because Box does not implement Comparable.

What you should do instead is add the generic constraint in the Box class:

class Box<T extends Comparable<T>> { ... }

Also, your count method is a bit too generic. It will probably make more sense if compeer's type is changed to Box<T> and list to List<Box<T>>.

The method signature now looks like this:

public static <T extends Comparable<T>> int count(List<Box<T>> list, Box<T> compeer) {

And you can implement the method like this:

return (int)list.stream().
filter(x -> x.name.compareTo(compeer.name) < 0).count();

Can't operator == be applied to generic types in C#?

"...by default == behaves as described above for both predefined and user-defined reference types."

Type T is not necessarily a reference type, so the compiler can't make that assumption.

However, this will compile because it is more explicit:

    bool Compare<T>(T x, T y) where T : class
{
return x == y;
}

Follow up to additional question, "But, in case I'm using a reference type, would the the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?"

I would have thought that == on the Generics would use the overloaded version, but the following test demonstrates otherwise. Interesting... I'd love to know why! If someone knows please share.

namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();

Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare<Test>(a, b);

}

static bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
}

class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}

public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}

Output

Inline:
Overloaded == called

Generic:

Press any key to continue . . .

Follow Up 2

I do want to point out that changing my compare method to

    static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}

causes the overloaded == operator to be called. I guess without specifying the type (as a where), the compiler can't infer that it should use the overloaded operator... though I'd think that it would have enough information to make that decision even without specifying the type.

In java, what is the exact meaning of each type parameter of a generic method in a type introduction?

It's hard to understand what exactly you're asking and what exactly you are confused about; I'll try answering your questions anyway.

Type parameters are placeholders for actual types, no matter whether you use them on a class or on a method. Note that this is exactly the same idea as with regular value parameters: they are placeholders for actual values that you supply when you call a method.

public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2)

This is a method with two type parameters, K and V, and two value parameters, p1 and p2.

When you call this method, you'll have to specify actual types for the type parameters, and actual values for the value parameters. In other words: you'll have to specify what types K and V are and you'll have to pass two instances of class Pair for p1 and p2.

The type parameters are "passed" to the type Pair in this example. So, the declaration of method compare means: I have a method named compare which takes two Pair objects with type parameters K and V. Instead of specifying actual, concrete types, I leave those as parameters. By doing this, you can call compare with any Pair with specific types for K and V.

For example, you can call compare with two Pair<Integer, String> objects. Or two Pair<BigDecimal, Long> objects, etc.

Are they placeholders for individual arguments passed into the method?

They are placeholders for types, just like regular parameters are placeholders for values.

Are they placeholders for type parameters passed to the actual object-type arguments passed into the method(i.e. Pair<K, V> //I view this as one unique type: class Pair<K, V> that receives two unique type parameters, K and V)?

Yes... (if I understand your question correctly). The method signature means that the method takes two Pair<K, V> objects, where you leave specifying the actual types to use for K and V to the caller of the method.

Or do generic methods require a unique type parameter for every variable they access whether they are passed as arguments to the method or arguments to an object, which is then passed into the method?

I don't understand what you mean by this question.

Typescript generic argument comparison

You can make use of type guards.

It would look something like this:

type Constructor<T extends {} = {}> = new (...args: any[]) => T;

function typeGuard<T>(o: any, className: Constructor<T>): o is T {
return o === className;
}

function createInstance<A extends Animal>(c: Constructor<A>): A {
if (typeGuard(c, Lion)) {
return new c('Lion initialized')
}
return new c();
}

Also please note the usage of Constructor<A> - you've mention that your constructors would receive parameters based on type - this can't be achieved by your implementation because your constructor definition doesn't receive any parameters and therefore you should use Constructor<A> to pass any number of parameters to constructor (it's up to you to pass correct arguments to correct type constructors).

Taking all that into account, I'd suggest a much cleaner and simpler approach. First define map of keys and corresponding types that can be created:

type TypeMap = {
"lion": Lion,
"bee": Bee
}

Then just create factory function which would suggest possible arguments ("lion" | "bee") on invoke, show error if unknown argument is entered and resolve correct return type.

function createSimpleInstance<T extends keyof TypeMap>(c: T): TypeMap[T] {
let instance: Animal;
switch (c) {
case "lion":
instance = new Lion("Lion initialized");
break;
case "bee":
instance = new Bee();
break;
default:
throw new Error("Unknown type");
}
return instance as TypeMap[T];
}

Great benefit of this is that within createSimpleInstance you are creating exact instances of Lion and Bee which helps you with autocomplete of exact arguments thats needed for each constructor function.

Please see playground.



Related Topics



Leave a reply



Submit