Stdlib soundness of option returning functions

未關閉
#9,233 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
5/5
預估耗時
一週以上
新手友好度
25/100
Issue 類型
功能
描述清晰度
基本清楚
活躍度
活躍
技術堆疊
ocaml

研究方向

Start by examining the standard library bindings for Array.shift, Array.pop, Array.get, and Map.get, then trace how option-returning functions are represented and compiled. The issue proposes several competing approaches, so first determine which behavior maintainers want; done means the selected approach makes these functions sound while addressing the interop edge cases raised.

由索引模型根據 Issue 內容生成。

描述

Array.shift, Array.pop, Array.get, Map.get, and likely others are unsound, see Playground.

Here is what a correct version of shift could be:

let shiftSafe = xs =>
  if xs->Array.isEmpty {
    None
  } else {
    let value = xs->Array.getUnsafe(0)
    let _ = xs->Array.shift
    Some(value)
  }

This is a common mistake when writing JS bindings and can be unexpected to users who expect ReScript to be a safe language.

I couldn't find a previous discussion, but I believe this needs a bit of consideration. The choices I see are:

  1. Implement safe ReScript version of Stdlib functions, rename the zero overhead to shiftUnsafe, getUnsafe, etc.
  2. Fix the compiler's handling of option-returning functions.
  3. Fix the representation of options.

Unfortunately, I think there will always be edge-cases that make (2) a losing battle. Even with correct code generation, people often use imprecise types for interop making compile-time information insufficient to prevent unexpected results. For example, users storing undefined containing data in a JSON type.

Similar to the previous reasoning, (3) is likely going to cause too many issues from users that are relying on a particular option implementation.

So I believe (1) is the correct choice for the standard library. However, this still makes the "obvious" implementation of JS bindings written by users prone to errors. One idea would be to generate a fixture by default unless disabled:

@send external shift: array<'a> => option<'a> = "shift"
@send @noInterop external shiftUnsafe: array<'a> => option<'a> = "shift"
// Stdlib_Array.bs.js
let shift = t => Primitive_option.some(t.shift())
主要語言
OCaml
星號
7.5k
分支
485
平均合併
17 小時 9 分鐘
30 天內合併 PR
264

環境準備

在 Codespaces 中開啟

在瀏覽器裡用你自己的 GitHub 帳號啟動這個專案的開發容器。

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

rescript-lang/rescript 的其他 Issue

查看 rescript-lang/rescript 的全部 Issue

相似的 Issue

更多 Backend & API Design Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。