+1 for these proposals:
-
HashMap<Vec-int, Vec-Rc-Cell-int>
or HashMap<Vec:int, Vec:Rc:Cell:int>
Or if just a whitespace is unambiguous then, for some reason, that looks cleanest imho:
HashMap<Vec int, Vec Rc Cell int>
+1 for these proposals:
HashMap<Vec-int, Vec-Rc-Cell-int>
orHashMap<Vec:int, Vec:Rc:Cell:int>
Or if just a whitespace is unambiguous then, for some reason, that looks cleanest imho:
HashMap<Vec int, Vec Rc Cell int>
Keep in mind that nested type parameter lists of more than one item exist.
Can your suggestion remain readable in cases such as this?
HashMap<Foo<int, A, B>, Bar<Vec<bool>, Qux<C, D, E>>>
How would this style
HashMap<Vec:int, Vec:Rc:Cell:int>
handle the first case?
Seems like the proposal's just path compression in a tree, and almost all your nodes have branches. Best you can do for that example is:
HashMap<Foo<int, A, B>, Bar<Vec:bool, Qux<C, D, E>>>
Guys, make sure you take into account #![feature(default_type_params)]
when offering your suggestions
In light of RFC 114 syntax: |: a, b, c| expr
, you could also use non-symmetric operators (I donāt think they look as clean though):
HashMap<Vec<String>, Vec<Rc<Cell<int>>>>
// Similar to `::` and `.` which seems good...
HashMap<Vec:.String, Vec:.Rc:.Cell:.int>
HashMap<Vec:-String, Vec:-Rc:-Cell:-int>
// Also problematic because of `<>`
HashMap<Vec:>String, Vec:>Rc:>Cell:>int>
// Easier with `[]`
HashMap[Vec:>String, Vec:>Rc:>Cell:>int]
// Probably don't want `:_` because of collision with _TypeName
HashMap<Vec:_TypeName, Vec:_Rc:_Cell:_int>
By the way, :
probably may not be good even if RFC 135 frees it up some because:
struct Point {x: A<B<C>>, y: A<B<C>> }
// Implies 2 different meanings of `:`
struct Point {x: A:B:C, y: A:B:C }
Defaults:
struct Vec<A, B = C:.D:.E>;
Spaces with <> or () for grouping is the best option in my opinion. It has the benefit of being unambiguous and easy on the eyes as well as including minimal punctuation for default types.
HashMap<Vec<String>, Vec<Rc<Cell<int>>>>
becomes
HashMap <Vec String> <Vec <Rc <Cell int>>>
which remains easy to read while avoiding the level of angle brackets with the lowest signal/noise ratio. Alternatively:
HashMap (Vec String) (Vec (Rc (Cell int)))
This system works very well for non-deeply-nested types, which is important for generics:
Option <Box T>
Result V <Box Show>
Box T
Ref 'a T
Default type params:
pub struct Type<V, A = Vec<String>, B = Default>
pub struct Type V A = <Vec String> B = Default
This seems like it could be made easier to look at with the addition of (optional) commas like so:
pub struct Type V, A = <Vec String>, B = Default
Does that take away from what you were going for?
Not necessarily. Mainly Iām looking to encourage the use of whitespace and remove the most inner pair of angle brackets, which, IMO, introduces the most noise.
bachmās example from before:
HashMap<Foo<int, A, B>, Bar<Vec<bool>, Qux<C, D, E>>>
// Reem's solution becomes (I think...I think it's tricky)
HashMap <Foo<int> <A> <B>> <Bar<Vec bool> <Qux<C> <D> <E>>
// iopq's solution
HashMap<Foo<int, A, B>, Bar<Vec bool, Qux<C, D, E>>>
It becomes
HashMap <Foo int A B> <Bar <Vec bool> <Qux C D E>>
Parens makes this easier to parse:
HashMap (Foo int A B) (Bar (Vec bool) (Qux C D E))
Itās worth noting that types rarely become this complicated without a type synonym or newtype being added along the way to break it up, and if they are this complicated it is usually an inferred type and you donāt really have to worry about it.
This seems Lisp-like, i.e. (op args)
rather than op(args)
. It is interesting that this makes multiple-arg types shorter, whilst the other suggestions make single-arg types shorter.
This actually makes single-arg types short also, because the parens are only for grouping, not application. HashMap<String, uint>
would be HashMap String uint
and Vec<String>
would be Vec String
.
You can combine ideas by using both shorthands:
// This is contrived
HashMap<Foo<int, A, B, C, D, E>, Bar<Vec<bool>, Qux<F<G<H<I<J>>>>>>>
// If `:` is for singles like `A<B<C>> => A:B:C`
// then with `space` `A<B,C,D,E> => A B C D E`
HashMap<Foo int A B C D E, Bar<Vec:bool, Qux:F:G:H:I:J>>
// Probably the same as:
HashMap<Foo int A B C D E, Bar Vec:bool Qux:F:G:H:I:J>
Also, I think :
looks nice in examples so I use it. Not strict about what symbol could be used. Iām definitely not used to A<B,C,D,E> => A B C D E
.
[EDIT]
Removed :+
(I thought an extra symbol was needed for some reason)
One possibility to get rid of the unfortunate angle brackets can be Reverse Polish notation (postfix notation):
HashMap<String, HashMap<String, int>>
becomes
String String int HashMap HashMap
and
HashMap<Vec<String>, Vec<Rc<Cell<int>>>>
becomes
String Vec int Cell Rc Vec HashMap
It works like a stack (think Forth, Factor or Joy). The only downside is that it wouldnāt work well with variadic generics.
Donāt forget the downside that itās basically impossible to know what is argument of what without knowing the exact arity of everyone, and counting the stack.
Reverse Polish notation is computer friendly, not human friendly.
And it will not work with HKT too (if Rust got them one day).
This also doesnāt work with default type parameters.
Iāve not done my homework on HKT, so Iāll ask you: might not operators between type names be a problem if types were first class citizens? E.g.:
HashMap<Vec-int, Vec-Rc-Cell-int>
// Vec-int
Does this imply that Vec-int
is int
subtracted from Vec
?
Then Vec-Rc-Cell-int
is int
subtracted from Cell
which is subtracted from Rc
subtracted from Vec
?
There isn't a lack of operators if that's a problem though and I've already presented many many and there are still more technically.
No need to be sarcastic here, a normal discussion would be fine...
That wasnāt sarcasm. I honestly didnāt understand and was asking if what I wrote is what you meant.