solargraph icon indicating copy to clipboard operation
solargraph copied to clipboard

Add support for literal tuples

Open apiology opened this issue 9 months ago • 5 comments

apiology avatar Mar 25 '25 10:03 apiology

This will be a bit of a change in user experience - folks will see e.g. Array(Integer, String) instead of just Array on foo = [1, "bar"].

I haven't experienced any shift in typechecking results from having more specific Array types hanging around - while I'm sure we'll want to add more logic in the future to be better on more explicitly handling Array() vs Array<>, at the moment Array(Foo, Bar) just gets treated as Array<Foo, Bar>, which seems perfectly fine. Glad we can get away with a small incremental change!

apiology avatar Mar 26 '25 13:03 apiology

I'm a big fan of expanding support for tuples, but I'm a little hesitant to infer tuples from literal arrays. I have some cases in my own projects where an array that's intended to be mutable gets initialized with default elements. I'd prefer them to be inferred as Array<X> instead of Array(X, Y, Z). It might be less of a problem in practice than I think, but I'd like to spend more time trying it out.

This kinda makes me wish Ruby had some equivalent to Elixir's native tuple type :/

castwide avatar Apr 05 '25 14:04 castwide

@castwide: In your case, would the types be varied? If not, I think I taught Chain::Array to create Array<X> instead of Array(X, X, X, X) or what have you for something like x = ["foo", "bar", "baz"]

If the types /are/ varied, https://github.com/apiology/solargraph/pull/4 has Array(X, Y, Z) treat Array<X, Y, Z> as its de-facto superclass, - so ideally it would degrade gracefully if you tried to mutate the array and still accept the operations. I could add some specs to explore that behavior and agree on what we want it to be and what it will take to get there.

I could perhaps even find the common superclass (e.g., Array(Integer, Float) could have a "superclass" of Array<Numeric>).

Another idea would be to treat this as a bit of a 'hidden' type - the LSP could show the Array<> types when the type is inferred, and the Array() version when the types are declared explicitly.

I'll dig in a little and find out what TypeScript and Mypy do in these situations (Steep and Sorbet as well if applicable)

apiology avatar Apr 06 '25 19:04 apiology

I could perhaps even find the common superclass (e.g., Array(Integer, Float) could have a "superclass" of Array).

That was one of the use cases that occurred to me. I might want array = [String, Integer] to be inferred as Array<Class> instead of Array(Class<String>, Class<Integer>). As I mentioned, that might be less of a problem in practice than I expect. Maybe we can merge it as is and determine whether we need to refine it after seeing it in action.

castwide avatar Apr 16 '25 16:04 castwide

That makes sense to me. I've been running with it for three weeks now and have been pretty happy with it, but I think we have options if folks want a more conservative approach too.

apiology avatar Apr 16 '25 16:04 apiology

I think we're ready to merge the tuple features into 0.56.0. I might suggest a couple refinements as I see them in action, but the fundamentals look solid.

Thanks again for all your hard work on this! :+1: :shipit:

castwide avatar Jun 23 '25 21:06 castwide