5 ms·
For the tuple example: from typing import TypeVar T, U, V, W = TypeVar('T'), TypeVar('U'), TypeVar('V'), TypeVar('W') def concatenate(a: tuple[T, U
by dazzlefruit 3y ago
For the tuple example:
from typing import TypeVar
T, U, V, W = TypeVar('T'), TypeVar('U'), TypeVar('V'), TypeVar('W')
def concatenate(a: tuple[T, U], b: tuple[V, W]) -> tuple[T, U, V, W]:
return a + b
For the generic type transformation example, I'm not sure what you mean:
from typing import Any, Callable
Transformer = Callable[[dict[str, Any]], dict[Callable, Any]]
This seems to match your question but it's really weird.
- Timon3 3y agoYour tuple example only works if both tuples have two elements. I specifically mentioned arbitrary fixed-size tuples (as in, tuples with an arbitrary non-variable length). Your generic type transformation example also doesn't come close to what Typescript does. The resulting dict will not have known keys based on the keys of the input dict. In Typescript I can write a function that takes an object with known keys, and it returns an object with those same keys having their values mapped to a different type, with the keys still known. I threw together a quick example - just look at the type of resultA/resultB by hovering over the variables[0]. But both are great examples - they are probably the closest you can get in Python, and they are so far removed from the thing I want to represent that they are completely useless. [0]: https://www.typescriptlang.org/play?#code/MYewdgzgLgBAhjAvDA3gKBjAZiEAuGKAJwFcBTAGgxgCM4iCs4AbCS6ugLwLBOeaoBfNGlCRYNJKmo58MACwAmKpjoMYAIgAWZfiBgB3EEWYATDStpxuMANoBdISKwkwwKAEtwhInEg4iAFsAeRoAKzJ3AB4AFRgyAA8oMjBTCBgAJUjjUyjoIg8wAHMKeDAATwA+SoAKEHCCGIBKAhQ7AGkYQpgAazJykCwYGPsCGqakSuHbdvsYQWlMIjIoEiIwGAB6TcIQUxA0YVFwaBhliD4oAEEpYj8IAJDwyKgauCbj8TOyC+YoACFbr5-MYnhF3DUaE0gA https://www.typescriptlang.org/play?#code/MYewdgzgLgBAhjAvDA...
- Izkata 3y agoTuples are already fixed size by nature, so adding a redundant "fixed-size" in that description was confusing. I also thought you meant a predefined size like always 2-tuples or always 3-tuples.
- Timon3 3y ago> Tuples are already fixed size by nature, so adding a redundant "fixed-size" in that description was confusing. No, you can type variable-length tuples in Python. A variable int tuple, for example, can be typed as Tuple[int, ...]. You can't concatenate two variable-length tuples, which makes sense - where would the cutoff be? But you should absolutely be able to concatenate two fixed-size tuples, and it's very limiting that you can't.
- Izkata 3y ago> A variable int tuple, for example, can be typed as Tuple[int, ...]. That's a type that matches tuples of any length, not a variable-length tuple. The size of a tuple can't be changed. A variable-length tuple doesn't even really make sense, what you'd want there is a list. > You can't concatenate two variable-length tuples, which makes sense - where would the cutoff be? But you should absolutely be able to concatenate two fixed-size tuples, and it's very limiting that you can't. This whole statement doesn't make sense. I'm assuming you're still talking about type definitions and not actually tuples.
- Timon3 3y ago> That's a type that matches tuples of any length, not a variable-length tuple. A tuple with a type that matches variable lengths of tuples is a variable-length tuple for that piece of code. You're free to show me some official definitions that proves this wording false, but until then it's useless nitpicking. Though you should probably take that up with Guido, who also calls them variable-length tuples: https://github.com/python/typing/issues/30 https://github.com/python/typing/issues/30 > This whole statement doesn't make sense. I'm assuming you're still talking about type definitions and not actually tuples. The statement makes perfect sense, thank you. If you have trouble understanding my messages without me repeating the whole definition every time, maybe just skip them.
- OrderlyTiamat 3y agoI think they've interpreted "variable length tuple" as "a tuple whose length can change", not "a tuple whose length could be one of multiple options". The former is of course not possible with tuples being immutable, which is why they're talking about lists.
- dazzlefruit 3y ago"Arbitrary fixed-size tuples" probably don't have a widely accepted meaning :) I read it as "size known when compiling the function". The second example is cool. But I can't find a good practical use case for either example. If you have a collection that's both heterogeneous and whose [size/key set] is statically known, when would it make sense to apply such generic transformations to them? This sounds like you have tuples or dataclasses where all elements have different meanings (since their types are fixed and different) _and_ you want to treat them like a generic collection _and_ you need the type checker to infer the result type. The main use of tuples or dataclasses or `NamedTuples` is to pass or return values to/from functions without dealing with long lists of arguments. The elements aren't in the same category, it doesn't make sense to process them as one big collection, they mean different things. (Also I think you made a mistake in your previous message, you wrote "an object with each key turned into a function" but it's the values that change types here.)
- Timon3 3y ago> "Arbitrary fixed-size tuples" probably don't have a widely accepted meaning :) I read it as "size known when compiling the function". That is exactly what I'm talking about - the size of the tuples is known statically. > The second example is cool. But I can't find a good practical use case for either example. There are many interesting use cases in libraries, especially for some of the more esoteric features. Everything can be used for additional type safety. > If you have a collection that's both heterogeneous and whose [size/key set] is statically known, when would it make sense to apply such generic transformations to them? This sounds like you have tuples or dataclasses where all elements have different meanings (since their types are fixed and different) _and_ you want to treat them like a generic collection _and_ you need the type checker to infer the result type. Simple example - I have functions that return a Rust-like Result type, and I want to transform that into a different tuple-based format using a decorator. The transformation itself is static, but I can't write one function that handles it all, because Pythons type system is simply not developed enough. Something that would be incredibly easy in Typescript. > The main use of tuples or dataclasses or `NamedTuples` is to pass or return values to/from functions without dealing with long lists of arguments. The elements aren't in the same category, it doesn't make sense to process them as one big collection, they mean different things. But I have a use case for exactly this feature. Why should the language limit me? Why should I implement x functions that take different tuple lengths, with me having to choose the correct one for each use case, when I could write one function that does all? > (Also I think you made a mistake in your previous message, you wrote "an object with each key turned into a function" but it's the values that change types here.) Sure, though I could also literally write a Map that turns all object keys into functions.
- chlorion 3y agoThe tuple thing requires variadic generics from my understanding. I don't thing variadic generics support is supported in most statically typed languages. The only one I can think of right now that supports this is C++.
- Timon3 3y agoTypescript supports it too (quick example[0]) :) and Python actually as well, but currently you can't unpack two TypeVarTuples in the same type expression: https://peps.python.org/pep-0646/ https://peps.python.org/pep-0646/ [0] https://www.typescriptlang.org/play?#code/C4TwDgpgBAglC8UDaA7ArgWwEYQE4BooBnYXASxQHMBdAKFEigCEFksB7dgGwgEMVC6bHjq0AxuxQkovAFzIhOAsVIUarJABYATIQBEACwhcu7KAHd2uLgBM9dCVOBQs8pB258BURSI0AzXi4iCEIABlF-NBQxYDJJKH9OAB4AFV4oCAAPYAgUGyJkADoS-hAkampCVKxMnLyC4tKUcsqAPgAKOSh0wlcerABKNxKi3qhRmuooAG9aKChcCGA0XBQmot5CUaw6AF9acUlpMVYk9i6+waOpTyLTSg6xQaA https://www.typescriptlang.org/play?#code/C4TwDgpgBAglC8UDaA...
- corethree 3y ago> I specifically mentioned arbitrary fixed-size tuples (as in, tuples with an arbitrary non-variable length). This is wrong. Again, Arbitrary fixed-size tuples are equivalent to structs with an arbitrary amount of properties. Languages shouldn't do this, it destroys the nature of what a TUPLE is which is essentially just a struct with no names. The concept you are going for is isomorphically encapsulated by ANOTHER type: List[Any] You should be using the above type to encode what you want conceptually. That being said if javascript has variadic tuples then it's not a very good type system imo. It encodes redundant concepts. Why have a tuple with Variadic arguments when I have Arrays that do the exact same thing?
- Timon3 3y ago> This is wrong. Again, Arbitrary fixed-size tuples are equivalent to structs with an arbitrary amount of properties. Languages shouldn't do this, it destroys the nature of what a TUPLE is which is essentially just a struct with no names. Okay, that might be your personal feelings on the topic. But do you understand the concept of "generic functions"? Sometimes you have to apply generic transforms to data. Being able to correctly express your transformations in a type system isn't "wrong", it's useful. > List[Any] Sorry, but I really think you don't understand what I'm talking about. If I write a function that handles tuples of arbitrary length and that function returns a transformed version of that tuple, I keep the information about individual tuple elements. This is thrown away in a list. > That being said if javascript has variadic tuples then it's not a very good type system imo. It encodes redundant concepts. Why have a tuple with Variadic arguments when I have Arrays that do the exact same thing? Arrays don't do the same thing, so they are not redundant concepts. Tuples have elements in specified positions with specified types. Arrays have one type (possibly a union type) over many elements.
- corethree 3y ago>Okay, that might be your personal feelings on the topic. But do you understand the concept of "generic functions"? Sometimes you have to apply generic transforms to data. Being able to correctly express your transformations in a type system isn't "wrong", it's useful. There's nothing like this in any type system I've seen. A struct with a generic amount of properties? Nonexistent. This isn't personal. This is the definition of a tuple. A tuple is a struct with no names. It is not a personal opinion. You can have generic functions that operate on generic types but there's no such thing as a struct with generic amount of properties. Closest thing is a list. >Sorry, but I really think you don't understand what I'm talking about. If I write a function that handles tuples of arbitrary length and that function returns a transformed version of that tuple, I keep the information about individual tuple elements. This is thrown away in a list. This isn't an opinion. There's no such thing as tuple types of arbitrary length unless the implementer decides to get hand wavy with the definition of what a tuple is. What you're talking about is only possible with dependent types. Very very few languages support this but the risk of doing this is it makes type checking undecidable. It's also extremely challenging to program this way. Does typescript support dependent types? Probably but that's outside the realm of normal programming it's most likely exists as obscure tricks. You're getting into Idris, proof checkers and such. Imagine this: func (x: Array[N], x:Array[M]) -> Array[M + N] where M and N is the size of the array. It's called dependent types because types are getting mixed with programming level terms. This is essentially what you need, but you want this level of type checking with structs/tuples. It's not just a "generic variable" It is much more then that: func(x: Tuple[*args1] y: Tuple[*args2]) -> Tuple[*(args1 + args2)] There's nothing wrong with this but once you get into this it's beyond traditional type systems. Practical programming rarely ventures to far into this world since it's really hard to even fully prove even trivial things. You'll see it's bringing the execution of programs into the type checking level. Maybe typescript has some shortcut that makes this level of type checking available for tuples, maybe that's what you're getting at. Unlikely that dependent types are supported generically. If ts Does supports dependent types, this is definitely something I did not know about. It does change the equation, but I suspect it's very much outside normal usage of the language. >Arrays don't do the same thing, so they are not redundant concepts. Tuples have elements in specified positions with specified types. Arrays have one type (possibly a union type) over many elements. Arrays are the thing you want for variadic containers. For memory optimized languages like rust or C++ arrays are defined with a size. Array[5] is a different type then Array[3]. You can define a "interface" that accepts generic arguments to arrays: func(a: Array[], b: Array[]) but you can't define the function above where a function creates a new type that's dependent on the internal types of a and b.