Possible Bug? I Can Create Generic Instance Ignoring Constraint

F# Generic constraint to have one generic type inherit from another

As from the F# spec:

New constraints of the form type :> 'b are solved again as type = 'b.

There are some popular F# language suggestions that aim to solve this, see:

https://github.com/fsharp/fslang-suggestions/issues/255

https://github.com/fsharp/fslang-suggestions/issues/162

Why does mypy ignore a generic-typed variable that contains a type incompatible with the TypeVar?

I think the problem here is that when you're constructing type alias, you're not actually constructing a new type -- you're just giving a nickname or alternate spelling to an existing one.

And if all you're doing is providing an alternative spelling to a type, that means that it it ought to be impossible to add any extra behavior while doing so. That's exactly what's happening here: you're trying to add additional information (your three type constraints) to Iterable, and mypy is ignoring them. There's a note saying basically this at the bottom of the mypy docs on generic type aliases.

The fact that mypy is just silently using your TypeVar without warning that its additional constraints are being ignored feels like a bug, actually. Specifically, it feels like a usability bug: Mypy ought to have raised a warning here and disallowed using anything other then unrestricted typevars inside your type alias.


So what can you do to type your code?

Well, one clean solution would be to not bother creating the Vector type alias -- or create it, but not worry about constraining what it can be parameterized with.

This means a user can create a Vector[str] (aka an Iterable[str]), but that's really no big deal: they'll get a type error the moment they try actually passing it into any function like your dot_product function that does use type aliases.

A second solution would be to create a custom vector subclass. If you do so, you'd be creating a new type and so can actually add new constraints -- but you'd no longer be able to pass lists and such directly into your dot_product classes: you'd need to wrap them in your custom Vector class.

This can be a little clunky, but you may end up drifting to this solution anyways: it gives you the opportunity to add custom methods to your new Vector class, which could perhaps help improve the overall readability of your code, depending on what exactly you're doing.

The third and final solution is to define a custom "Vector" Protocol. This would let us avoid having to wrap our lists in some custom class -- and we're creating a new type so we can add whatever constraints we want. For example:

from typing import Iterable, TypeVar, Iterator, List
from typing_extensions import Protocol

T = TypeVar('T', int, float, complex)

# Note: "class Vector(Protocol[T])" here means the same thing as
# "class Vector(Protocol, Generic[T])".
class Vector(Protocol[T]):
# Any object that implements these three methods with a compatible signature
# is considered to be compatible with "Vector".

def __iter__(self) -> Iterator[T]: ...

def __getitem__(self, idx: int) -> T: ...

def __setitem__(self, idx: int, val: T) -> None: ...

def dot_product(a: Vector[T], b: Vector[T]) -> T:
return sum(x * y for x, y in zip(a, b))

v1: Vector[int] = [] # OK: List[int] is compatible with Vector[int]
v2: Vector[float] = [] # OK: List[float] is compatible with Vector[int]
v3: Vector[str] = [] # Error: Value of type variable "T" of "Vector" cannot be "str"

dot_product(v3, v3) # Error: Value of type variable "T" of "dot_product" cannot be "str"

nums: List[int] = [1, 2, 3]
dot_product(nums, nums) # OK: List[int] is compatible with Vector[int]

The main disadvantage to this approach is that you can't really add any methods with actual logic to your protocol that you can reuse between anything that might be considered a "Vector". (Well, you sort of can, but not in any way that'll be useful in your example).

How to impose generic constraints to the parameters and return values of a function argument of a generic Kotlin function?

This unexpected behavior was caused by a bug in the Kotlin >=1.4 compiler.
This bug can be tracked here: https://youtrack.jetbrains.com/issue/KT-48935.

Is there a constraint that restricts my generic method to numeric types?

This constraint exists in .Net 7.

Check out this .NET Blog post and the actual documentation.

Starting in .NET 7, you can make use of interfaces such as INumber and IFloatingPoint to create programs such as:

using System.Numerics;

Console.WriteLine(Sum(1, 2, 3, 4, 5));
Console.WriteLine(Sum(10.541, 2.645));
Console.WriteLine(Sum(1.55f, 5, 9.41f, 7));

static T Sum<T>(params T[] numbers) where T : INumber<T>
{
T result = T.Zero;

foreach (T item in numbers)
{
result += item;
}

return result;
}

INumber is in the System.Numerics namespace.

There are also interfaces such as IAdditionOperators and IComparisonOperators so you can make use of specific operators generically.

Generics class method taking function parameter of the generic type doesn't work with Void

You can trick the type inference to almost ignore the missing argument like so:

class Test {
static var test2 = new Test2();
static public function main() {
test2.test(passedFunc);
}
static function passedFunc(?unused):Void {
trace("passedFunc");
}
}
class Test2<T> {
public function new():Void {}
public function test(func: T->Void) {
trace("Test2.testFunc(T)");
}
}


Related Topics



Leave a reply



Submit