6 ms·
No this is actually wrong. It works but it doesn't capture the meaning of the nature of a tuple. A Tuple is Typed as something as a Fixed size. That's right, i
by corethree 3y ago
No this is actually wrong. It works but it doesn't capture the meaning of the nature of a tuple.
A Tuple is Typed as something as a Fixed size. That's right, it's like this at the Type level. The entire concept of a tuple is a Product type or essentially like a struct but with no names for each parameter.
Tuple[int, str, float] #correct
Doing what you're doing here is equivalent to creating a Struct with variadic properties.
If you want some container that holds an arbitrary amount of things that is a List
The correct type for what you want is actually this:
List[Any]
- Timon3 3y agoIt absolutely isn't wrong, and it's strange that you have some aversion against it. Think of Tuple[int, ...] as a union of Tuples of all lengths containing only ints. It's a specific language feature, and it's not "wrong" in any way. And I have no idea why you claim that a list is "correct".
- corethree 3y agoYou're thinking fixed size arrays. It doesn't make sense to have tuples of arbitrary size. To make it arbitrary size you have to constrain it on a single generic parameter which makes it functionally equivalent to a fixed size array. You essentially just do this with an array or a list. Read my other reply to you to see the problem of taking functions with "generic" number of parameters. What are you going to do with each parameter? What are the types of each parameter? You can't do anything other then breaking out of the type system. Basically you're filling those tuples with a bunch of "Any" types. So what's the point of the type system now? There is No point. Just like List[Any] To get your idea to work you need dependent types.
- dragonwriter 3y ago> To make it arbitrary size you have to constrain it on a single generic parameter Your information is out of date since Python 3.11: https://peps.python.org/pep-0646 https://peps.python.org/pep-0646
- corethree 3y agoBro, Look at this: https://peps.python.org/pep-0646/#multiple-type-variable-tuples-not-allowed https://peps.python.org/pep-0646/#multiple-type-variable-tup... Does this not exactly mean: "To make it arbitrary size you have to constrain it on a single generic parameter"
- dragonwriter 3y ago> Bro, Look at this: I’m not your bro and I've been discussing what that PEP does and does not allow in every post in this subthread. > Does this not exactly mean: "To make it arbitrary size you have to constrain it on a single generic parameter" No, it doesn't: Ts = TypeVarTuple(*Ts) def f(cond: Callable[[],bool], t: tuple[*Ts]) -> None | tuple[*Ts]: ... The parameter t is an arbitrary-sized (and shaped) tuple, and the return value of f has the same shape as the parameter it is called with. No multiple unpacking means you can't type things like concatenations of arbitrary-shaped tuples without losing type specificity (and resorting to just tuple), but it doesn't mean you can't type functions using arbitrary sized and shaped tuples outside of that restriction.
- corethree 3y ago>I’m not your bro and I've been discussing what that PEP does and does not allow in every post in this subthread. It's called an expression. It's a common one in the US and in countries that have English as a first language. >No, it doesn't: Lol yes it does. I said what I said and meant what I meant. I'm in control of that you aren't. What's going on here is that you either misinterpreted it or you're just wrong. >No multiple unpacking means you can't type things like concatenations of arbitrary-shaped tuples without losing type specificity (and resorting to just tuple), but it doesn't mean you can't type functions using arbitrary sized and shaped tuples outside of that restriction. You literally and I mean literally re-explained what I meant. Then Proceeded to imply I meant something else. Read it: to make a parameter of arbitrary type you have to constrain it on a single parameter. Word for word. Don't twist it.
- Timon3 3y ago> You're thinking fixed size arrays. It doesn't make sense to have tuples of arbitrary size. My god. No, Python doesn't support "fixed size arrays", but it does support tuples of arbitrary size, no matter how often you claim that to be wrong. > Read my other reply to you to see the problem of taking functions with "generic" number of parameters. What are you going to do with each parameter? What are the types of each parameter? You can't do anything other then breaking out of the type system. Basically you're filling those tuples with a bunch of "Any" types. So what's the point of the type system now? There is No point. Just like List[Any] I could, for example, do the thing I've been writing dozens of replies asking for: concatenate two arbitrary tuples. It's a perfectly well-defined operation, and without an artificial limitation on unpacking of TypeVarTuples, it would already be possible. It is already possible to do what you claim impossible with one arbitrary tuple. How can that be? You keep going on and on about how that doesn't work. Why does it?
- corethree 3y ago>My god. No, Python doesn't support "fixed size arrays", but it does support tuples of arbitrary size, no matter how often you claim that to be wrong. My god I never claimed this. I'm just talking about programming in general. I'm trying to show you that what YOU are asking for is programming operations to happen at the type level. You're not seeing it correctly. >I could, for example, do the thing I've been writing dozens of replies asking for: concatenate two arbitrary tuples. It's a perfectly well-defined operation, and without an artificial limitation on unpacking of TypeVarTuples, it would already be possible. You're not getting it. Ok let me spin it to you another way. Imagine you Do have two tuples that you concat: function concat(x: Tuple[*arg1], y: Tuple[*arg2]) -> Tuple[*(arg1 + arg2)]: Right? You notice the plus operator at the end there where I concatenate all the generic arguments and unroll it right? You're saying TS supports this and that it's common languages to support that "common" operation. Well here's another common operation. What if I want the INTERSECTION of the two tuples? function intersect(x: Tuple[*arg1], y: Tuple[*arg2]) -> Tuple[*(arg1 | arg2)]: You see what's going on here? You're asking for programming operators like concat and intersect and union INSIDE of types. You are asking for features that DON'T EXIST in practical type based languages. These features exist in academic languages. And those academic languages are completely off topic. That's what I'm getting at. Read it and understand it. >I could, for example, do the thing I've been writing dozens of replies asking for: concatenate two arbitrary tuples. It's a perfectly well-defined operation, and without an artificial limitation on unpacking of TypeVarTuples, it would already be possible. You can do this and define a function that does this in python and likely typescript. But you would be EXITING the type system when you do this. That means using keywords like Any and potentially running into runtime errors. I want to bold that part above. I'm pretty sure whatever you're doing either uses a bunch of Any's which DOES not preserve the shape fully. This is likely what's going on. It may pass the type check but it's not doing what you mentioned in your initial post which is Preserving the shape of the type. I haven't used typescript. But IF what you say about typescript is TRUE and that it type checks the concatenation of shapes then it's likely an arbitrary one off feature. Have a look at those functions again: function concat(x: Tuple[*arg1], y: Tuple[*arg2]) -> Tuple[*(arg1 + arg2)]: function intersect(x: Tuple[*arg1], y: Tuple[*arg2]) -> Tuple[*(arg1 | arg2)]: Basically you're saying that you want some language that supports type level programming where you can concat types, intersect types, divide types, likely bring programming terms up into the type level and have propositional terms like func add(x: int < M, y: int < N) -> int < M + N - 1 All of this is unlikely to be supported by any practical language. Likely TS has a one off where if you do this: func concat(x: Tuple[*args], y: Tuple[*args]) -> Tuple[M]: return x.concat(y) Where x.concat(y) is just special in that it is the only method that instantiates a typed tuple that is the concatenation of both tuples. Again I repeat it is unlikely for typescript to support what you are asking for in a very generic way where you can program your types.
- dragonwriter 3y ago> It works but it doesn't capture the meaning of the nature of a tuple. That's backwards. It doesn't work (as noted in GP, because Python supports unpacking only a single variadic parameter in a type annotation), but it does capture the nature of a tuple. It is (or, more precisely, would be, if the syntactic limitation was relaxed to allow it) a generic function that operates on two tuples of arbitrary tuple types and returns a tuple of a third tuple type whose shape is a simple concatenation of the shapes of the input tuples. > Doing what you're doing here is equivalent to creating a Struct with variadic properties. Well, a "struct" in Python is a particular low-level byte-mapped datatype, but the generic concept of a Struct differs from a tuple in two ways -- fields identified by name and that Structs are generally mutable. > If you want some container that holds an arbitrary amount of things that is a List But... I don't want that, and that's not what this works on. There's a difference between a function that works on containers of changeable length and a generic function that works on immutable containers (so, fixed length and contents), but is adaptable to any length (or more specifically, shape, including not only length by order of types of elements) of arguments, producing a result of a container type whose shape is strictly determined by the shapes of the inputs, with the shapes statically verifiable. Python is very close to allowing that, which is very different than: def concat(l1: list, l2: list) -> list: ... which is a fine function, but not at all what the other one is about.
- corethree 3y ago> a generic function that operates on two tuples of arbitrary tuple types and returns a tuple of a third tuple type whose shape is a simple concatenation of the shapes of the input tuples. This isn't definable without dependent types or a concat operator at the type level. Dependent types aren't a thing we are talking about here and languages that support this feature are waaay out of scope. You're basically asking for stuff like this: func concat(a: Array[int; M], b Array[int; N]) -> Array[int; N + M] or func concat(a: Tuple[*args1], b Tuple[*args2]) -> Array[*(args + args)] Which is bringing those programming terms up a level into types. This doesn't exist in the realm of programming we're talking about. Idris, Lean and Coq are more you're game here and those languages are clearly off topic. >But... I don't want that, and that's not what this works on. You want something well out of scope of this conversation and well out of scope of most practical programming languages. You still don't get what a tuple is. Nobody defines a Product type with an arbitrary amount of properties anymore then someone defines a struct with an arbitrary amount of properties anymore then they would do it for a tuple. This is NOT the definition of a tuple. People are confusing the Tuple for some Immutable list. >Python is very close to allowing that, which is very different than: Python shouldn't allow this, neither should TS. If typescript allows it, it's probably some arbitrary shortcut feature. Dependent types at the type level supported in a very generic way is very very unlikely. Like you people are trying to explain to me what a generic is while doing all kinds of programming operations on type level entities like concatenating them and combining shapes. Is the concat the only way to do it? What about an intersection? These operators only come into play with advanced theoretical langauges like Lean or Idris and it's very off topic.