syntax icon indicating copy to clipboard operation
syntax copied to clipboard

Feature suggestion: syntax for Js.Dict.t literals

Open johnridesabike opened this issue 5 years ago • 6 comments

I've been working with code that uses "hash map" style JS objects, and the ReScript syntax for declaring them can be tedious. (Or rather, the lack of syntax to declare them is tedious.)

Consider this JS:

const data = {
  a: foo,
  b: bar,
  c: baz,
};

Compared with this ReScript:

let data = Js.Dict.fromArray([
  ("a", foo),
  ("b", bar),
  ("c", baz),
])

That's a lot of extra parentheses and brackets to express the same thing. When you inline it somewhere (such as inside a function argument), then it's even more noisy and less readable.

My suggestion is to include a dedicated syntax similar to Js.t objects. Maybe something like this:

@dict
let data = {
  "a": foo,
  "b": bar,
  "c": baz,
}

Would this make sense to add?

johnridesabike avatar Nov 20 '20 17:11 johnridesabike

I think we could even have a generic system for simple, literal keys:

// Js.Dict
dict{
  "a": 1,
  "b": 2,
  "c": 3,
}

// Belt.Map.String
map{
  "a": 1,
  "b": 2,
  "c": 3,
}

// Belt.Map.Int
map{
  1: 1,
  2: 2,
  3: 3,
}

set{1, 2, 3} // Belt.Set.Int
set{"foo", "bar", "baz"} // Belt.Set.String

bloodyowl avatar Nov 20 '20 20:11 bloodyowl

That would be cool if it was possible, although that would have to still desugar/compile to function calls, right? Js.Dict can potentially compile to an object literal, which seems much simpler.

johnridesabike avatar Nov 21 '20 02:11 johnridesabike

I think I saw an issue on the compiler that @bobzhang opened some time ago that discussed the possibility to convert ˋfromArray` calls with literal to the data structure itself. I think it'd be fairly easy for dicts, but not sure about Belt data structures.

bloodyowl avatar Nov 21 '20 08:11 bloodyowl

@bloodyowl: Love this approach!

jfrolich avatar Nov 23 '20 09:11 jfrolich

@bloodyowl if calls to Js.Dict.fromArray with a literal array would be compiled directly to the given json object then it would totally make sense to have a dedicated syntax. But I wouldn't mind the slight runtime cost meanwhile. I couldn't find the issue though, are you talking about rescript-lang/rescript-compiler#2320 ? It's more than 3 years old, I hope it'll get more love now ^^

tsnobip avatar Feb 11 '21 10:02 tsnobip

@bloodyowl I would very much be in favor of that.

My use case in case there's a better way

module Icon = {
  @react.component
  let make = (~icon: option<string>=?) => {
    <img src={icon->Option.getWithDefault("/img/default-icon")} />
  }
}

module LabelWithIcon = {
  @module external hobbyIcon: string = "./hobby.svg"
  @module external memoryIcon: string = "./memory.svg"
  @module external standardIcon: string = "./standard.svg"
  let icons = Js.Dict.fromArray([
    ("Hobby", hobbyIcon),
    ("memory", memoryIcon),
    ("standard", standardIcon),
  ])

  @react.component
  let make = (~id: string, ~label: string) => {
    <label><Icon icon={icons->Js.Dict.unsafeGet(id)} />{label->React.string}</label>
  }
}

My rationale is that explicitly typing all the possible ids with a Record would be rather tedious. Additionally by definition of this type it does not really matter if an icon displays or not, it's a nice-to-have, but no one is going to miss them if they don't display. The fromArray works but it's a bit of a roundabout way to get there so a direct syntax would be awesome!

jaidetree avatar Jun 10 '21 03:06 jaidetree