Alternatives to nested angle brackets

I don’t really know what you mean by subtracting actual types.

From what I understand, his HashMap<Vec-int, Vec-Rc-Cell-int> is equivalent to

HashMap<Vec<int>, Vec<Rc<Cell<int>>>>.

Exactly! Should Vec-int mean that a new type is constructed when combining two types with an operator?

Vec:Rc:Cell:int perhaps could be defined to mean the type Vec<Rc<Cell<int>>>

The choice of combinator/operator may have to be suited to the types of abstractions that are meaningful on types. For example, the type (int * int) could be used to mean a second degree int. (Meters / Second) would be another type, and so on...

How does your proposition fit with HKT?

I’d like template type instantiations to look like these:

Vec|Int

Array[Uint, 3]

Box|Map[Str, Int64]

Using square brackets (similar to the indexing operator) for template arguments makes sense if you think of a type template as an infinite array of types.

Pulling on that thread, indexing operator could also use the shorthand x|i for the single argument case:

let mut values: Array[int, 3] = { 11, 22, 33 };
values|2 = 66;

Multi-argument indexing would have to use the long format x[i, j, k, ...]:

let mut grid: Array[int, 3, 5] = { {111, ..3}, ..5 };
grid[2, 4] = 222;
2 Likes

I don't know a thing about HKT. I was just trying to combine ideas from 2 different groups so people could see it without having to think about it.

I like the idea a single pipe is already used for the BitOr operator and println!("%d", values|2) would expand to println!("%d", values.bitOr(2)).

+1 to square brackets. I’ve only used C++, but looking elsewhere scalas’ choice of square-brackets for type-params and (index) looks great. a collection has some theoretical similarity to a pure function, and vica versa. Given iterator code, indexing is less common than type-params.

I gather rust used to use square brackets, and I would guess it’s far too late to go back.

It makes sense in Haskell/ML because everything is curried. The syntax reflects the semantics. Polymorphic type constructors in those languages have the kinds:

  • * -> *
  • * -> * -> *
  • * -> * -> * ... -> *

Rust's type constructors on the other hand would look more like:

  • (*,) -> *
  • (*, *) -> *
  • (*, *, ...) -> *

Why not just replace angular brackets entirely by square brackets? It’s much easier on the eyes and it keeps the semantics of nesting very clear without much mental processing.

I think HashMap[Vec[int], Vec[Rc[Cell[int]]]] looks better than HashMap<Vec<int>, Vec<Rc<Cell<int>>>>

Even better looking would be parentheses, but that would probably confuse with the other parentheses in function calls.

HashMap(Vec(int), Vec(Rc(Cell(int))))

Because using square brackets makes it look too much like indexing. Furthermore, angle brackets for generics are already familiar to C++ programmers (being one of the main audiences), as well as Java and C# programmers.

If you find yourself needing that complex types you should probably create type aliases or intermediate abstractions, anyhow. Also, HashMap<Vec<int>, Vec<Rc<Cell<int>>>> does not convey what information is being processed/stored. From a maintenance perspective it’s awfully opaque.

Lastly, I bet types this complex are rather uncommon. How often do you really need the key of a hashmap to be a vector of ints?

looks like indexing? that’s no argument. “tuple struct initializing with parentheses makes it look too much like a function call”. “struct initialization with braces makes it look too much like a block”, “using less than and greater than for generics makes it look too much like a comparison”

such things happen, because we only use ASCII. i’d be fine with chevrons: HashMap⟨Vec⟨int⟩, Vec⟨Rc⟨Cell⟨int⟩⟩⟩⟩, but since we don’t go this road, we have to overload things.

scala (among others) uses brackets for generics and they are much better:

  1. they are an actual type of framing character unlike < and >, so editors highlight matching brackets
  2. “indexing” is actually an useful metaphor for generics: “use this specialization of that type”
  3. as < and > are comparison operators, they align with other operators like +, -, = in good fonts, i.e. they have a raised baseline and are about as high as a lowercase character. type of framing characters ()[]{} are full height or higher and start below the text baseline or on it, which serves well to actually frame things they contain.

i’m sad that my opinion seems to be losing out here although i haven’t heard many valid counter arguments, and no good ones. HashMap[Vec[int], Vec[Rc[Cell[int]]]]

2 Likes

Would square brackets allow replacing foo::<bar,baz> with foo[bar,baz]

so I realise there’s ambiguity… in some contexts, foo[bar,baz] could be an array index or type-parameters on a function. (anything else?); but in either case, its a single node in the AST yielding a value

let x:foo[bar,baz] = ... // thats a type x = foo[bar,baz]{......} // that must be a type, because its’ followed by {…struct initialiser…} foo[bar,baz](a,b,c); // Thats ambiguous - could be variable[index expression] or function-name[types](arguments) // however the overall shape of the AST is the same, unlike with <… > ambiguities // once you’ve found the definition of ‘foo’ (a function? a variable?) could you figure out that it’s a function call, and swap the meaning of the node? in either case the foo[bar,baz] had to yield a callable.

Does that stretch the goal of simple parsing too far? I think rusts’ grammar for types is slightly different - but part of that is the angle brackets themselves; and if you want to pass computed values into type-parameters like C++ can, you’d want more of the regular grammar.

I guess there must be a reason why scala switched to something(index)

could expressions and types be given the same grammar, and then use other operators to give more meaning when taking types, e.g. Vec.Option.int could be shorthand for Vec[Option[int]], and I gather some languages use a|b for anonymous variants (which sounds great to me)

(this would mean one namespace instead of separate namespaces for types/functions?)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.