rescript-lang.org icon indicating copy to clipboard operation
rescript-lang.org copied to clipboard

Cheat sheet for annotations

Open cristianoc opened this issue 1 year ago • 9 comments

Present a compact cheat sheet for decorators relevant for code generation. Here's a list of all decorators. Irrelevant ones to be removed:

  • ~@@deprecated~
  • ~@@warning~
  • [x] @as only used for runtime representation, except for default arguments @as("someString") _
  • [email protected]~
  • ~@dead~
  • ~@deprecated~
  • ~@deriving~ About runtime representation
  • ~@doesNotRaise~
  • ~@genType~
  • [x] @get
  • [x] @get_index
  • [x] @ignore
  • ~@inline~
  • ~@int~ not relevant: about runtime representation
  • ~@live~
  • ~@meth~ About runtime representation
  • [x] @module
  • [x] @new
  • [x] @obj
  • ~@raises~
  • [email protected]~
  • [ ] @return This mixes runtime representation and externals: a post-processing for results
  • [x] @scope
  • [x] @send
  • [x] @set
  • [x] @set_index
  • ~@string~ not relevant: about runtime representation
  • [ ] @this Requires annotations on both external and uses
  • ~@unboxed~ About runtime representation
  • [ ] @uncurry This guarantees that the curried function is treated as if it were uncurried
  • [ ] @unwrap Unwraps one level of unary polymorphci variants (e.g. [#Int(int) | #Str(string)]). Should probably be a language-level feature either<(int, string)>.
  • [x] @val
  • [?] @variadic Should this be a language-level feature?

A few examples covered:

// @val
// external setTimeout: (unit => unit, int) => timeoutID = "setTimeout"
external setTimeout: (unit => unit, int) => timeoutID = "setTimeout($1, $2)"

// @get external getName: window => string = "name"
external getName: window => string = "$1.name"

// @set external setName: (window, string) => unit = "name"
external setName: (window, string) => unit = "$1.name = $2"

// @get_index external get: (t, string) => int = ""
external get: (t, string) => int = "$1[$2]"

// @set_index external set: (t, string, int) => unit = ""
external set: (t, string, int) => unit = "$1[$2] = $3"

// @module("path")
// external dirname: string => string = "dirname"
external dirname: string => string = "import(path).dirname($1)"

// @new external create: unit => t = "Date"
external create: unit => t = "new Date()"

// @send external getElementById: (document, string) => Dom.element = "getElementById"
external getElementById: (document, string) => Dom.element = "$1.getElementById($2)"

// @module("library-x")
// @val external doStuff: (@as(json`{format:"utf8", includeStuff: false}`) _, string) => string = "doStuff"
external doStuff: string => string = "import(library-x).doStuff({format: 'utf8', includeStuff: false}, $1)"

// @val external doSomething: (@ignore 'a, 'a) => unit = "doSomething"
external doSomething: ('a, 'a) => unit = "doSomething($2)"

// @obj
// external action: (~name: string, unit) => _ = ""
external action: (~name: string, unit) => _ = "{name:$1}"

// @scope("Math") @val
// external floor: float => int = "floor"
external floor: float => int = "Math.floor($1)"

cristianoc avatar Oct 10 '22 07:10 cristianoc

How to describe the difference between @scope and @module ?

cristianoc avatar Oct 10 '22 08:10 cristianoc

I didn't know, but are the $1, $2 placeholder a thing?

IwanKaramazow avatar Oct 10 '22 08:10 IwanKaramazow

Just a compact notation to describe what the examples do. But once all the uses of attributes are lined out, it might suggest a decent universal representation.

cristianoc avatar Oct 10 '22 08:10 cristianoc

Looks like @variadic can be moved to the language in principle e.g. little prototype: https://github.com/rescript-lang/rescript-compiler/issues/5727

So it becomes about runtime representation and not about FFI.

cristianoc avatar Oct 10 '22 17:10 cristianoc

Just used import(-) to mark @module things. Just as a notation to differentiate from @scope. And removed @variadic. This gives a pretty small, self-contained set of things that can be expressed.

cristianoc avatar Oct 11 '22 09:10 cristianoc

Since import wasn't well received, a couple of ideas for importing values from javascript:

external "path" {
  dirname: string => string,
  renameSync as rename: (string, string) => string,
  "weird identifier" as ident: unit => unit
}

// entire module contents
external "leftPad" {
  * as leftPad: (string, int) => string
}

// import default export
external "./modules/school.js" {
  default as schoolName: string,
}
// or simply: (this could be too much)
external "./modules/school.js" as schoolName: string

IwanKaramazow avatar Oct 14 '22 07:10 IwanKaramazow

@cristianoc is this issue about having a separate page that lists all possible constructs in one example? Or are you talking about extending our syntax lookup, that lists all the decorators already?

image

ryyppy avatar Feb 03 '23 09:02 ryyppy

@cristianoc is this issue about having a separate page that lists all possible constructs in one example? Or are you talking about extending our syntax lookup, that lists all the decorators already?

image

This is not necessarily about description only. It could be a different way to express FFI in future. Perhaps not super relevant for the doc site right now.

cristianoc avatar Feb 03 '23 09:02 cristianoc

A few additional comments from discussions with folks

@val standalone binds to globals. But in any recent JS version you wouldn’t need that anymore. There’s a global object now

I’m not sure how useful @this is. Binding to modern libraries that use OOP is a challenge. A mere @this might not be enough anyway

I’m not sure @scope is needed because we can just special-case a few built-ins like Math and others in @module

cristianoc avatar Apr 06 '23 03:04 cristianoc