Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Overload square bracket for both array and vector initialization #364

Closed
Yu-zh opened this issue May 6, 2024 · 3 comments
Closed
Labels

Comments

@Yu-zh
Copy link
Contributor

Yu-zh commented May 6, 2024

Motivation

The Vec datatype is used frequently but for now we have to write @vec.Vec::[1, 2, 3] to create a vector with init elements. It's even worse when we want to write nested vectors like: @vec.Vec::[@vec.Vec::[1, 2, 3], @vec.Vec::[4, 5, 6]].

By contrast, Array is used less often but has a more handy syntax. So we could overload the [1, 2, 3] syntax so that it creates either an array or a vector according to its context. Vector is favored when the context is unclear. For example:

fn init {
  let v = [1, 2, 3] // `v` is inferred to have type Vec[Int]
  let a: FixedArray[_] = [1, 2, 3] // `a` type annotation is required for fixed array
  let vv = [[1, 2, 3], [4, 5, 6]] // `vv` has type Vec[Vec[Int]]
  let aa = [a, [4, 5, 6]] // since `a` is fixed array, the typer knows [4, 5, 6] is also a fixed array, so the type of `aa` is FixedArray[FixedArray[Int]]
}

This is also consistent with some other language features in Moonbit. In particular, we are using [ a, b, .. ] for pattern matching on both Vector and Array. Also, the data constructors are disambiguated by the typing information from the context.

Comments and suggestions are appreciated.


Edit: vector type annotation is not required in the example

@Yu-zh Yu-zh added the proposal label May 6, 2024
@shamiao
Copy link

shamiao commented May 7, 2024

With all due respect, I'm not quite for this proposal, since this may cause 2 consistency problems.

A) Inferred data type differs when the initialization value appears as literal or variable binding:

// use syntax from this proposal
let vec1: @vec.Vec[_] = @vec.Vec::[[1, 2]]  // inferred - vec1 @vec.Vec[@vec.Vec[Int]]
let arr2 = [1, 2]  // same literal value  // inferred - arr2: Array[Int]
let vec2: @vec.Vec[_] = @vec.Vec::[arr2]  // inferred - vec2: @vec.Vec[Array[Int]]

B) to_string() result differs from initialization syntax:

// use syntax from this proposal
// ↓↓↓ assigned with array syntax here...
let vv: @vec.Vec[@vec.Vec[Int]] = @vec.Vec::[[1,2], [3,4], [5]]
// ↓↓↓ printed as explicit vec syntax here?
println(vv.to_string())  // Vec::[Vec::[1, 2], Vec::[3, 4], Vec::[5]]

In my opinion, Array[T] is a basic primitive type that ALWAYS deserves a unique and simply literal value format without any ambiguity. Any high-level type is not suggested to interfere the syntax of primitive types.

In fact, the real difficulty is how to shorten the initialization syntax of Vec[T], especially the @vec. part. Although not perfect, I think a use syntax from Rust language may be useful:

use @vec.Vec

fn main {
    let v = Vec::[Vec::[1, 2], Vec::[3, 4]]
    println(v.to_string())
}

The prelude mechanism of Rust language may also be introduced.

@Yu-zh
Copy link
Contributor Author

Yu-zh commented May 7, 2024

@shamiao Thanks for sharing your thoughts.

Sorry my original example was confusing, the type annotation is not required if vector is the desired type:

fn init {
  let v = [1, 2, 3]  // v: Vec[Int]
  let vv = [v, [4, 5, 6]] // vv: Vec[Vec[Int]]
}

A) Since the vector type is favored in unclear context, we'd have

let arr2 = [1, 2]   // inferred - arr2: Vec[Int]

B) We will also change the way how vectors and fixed arrays are transformed to string to make things consistent.

C)

In my opinion, Array[T] is a basic primitive type that ALWAYS deserves a unique and simply literal value format without any ambiguity. Any high-level type is not suggested to interfere the syntax of primitive types.

FixedArray[T] can still use the syntax [1, 2, 3]. MoonBit disambiguate basic operators like +, a[i](indexing), etc, according to the type information, so I think making the array construction operator one of them is reasonable.

@shamiao
Copy link

shamiao commented May 7, 2024

@Yu-zh Thank you very much. I basically agree with the core idea of edited proposal, with some minor different details:

(some ideas have already mentioned in MoonBit 用户交流群 WeCom group )

A) Remove the concept of array from primitive types. All linear collections should be provided by core as high-level types.

B) Rename struct Vec[T] to struct Array[T] and use it as the only grow-able array of MoonBit.

Actually, naming grow-able array 'vector' is a historical mistake from C-like low-level languages. The name vector is abandoned by many recent GC programming languages, we also have a chance to adapt now.

C) Thus, [1, 2] can be simply considered as a shorthand of initializing Array[T] (== old Vec[T]).

D) Consider struct FixedArray[T] as just another high-level type. Since it's fewer used, it's ok to provide no shorthand for it.

@Yu-zh Yu-zh closed this as completed May 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants