Skip to content
New issue

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

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

Already on GitHub? # to your account

Add option to not include undefined values in resulting object literal #801

Open
jchavarri opened this issue May 13, 2019 · 7 comments
Open

Comments

@jchavarri
Copy link
Contributor

Using

let obj = object%js (self)
  val z = Js.undefined [@@jsoo.optdef]
end

It still includes {z: undefined} in the resulting object literal. It'd be helpful to have an option (or a new attribute) to just not include the property altogether if it's undefined.

BuckleScript has something similar with bs.obj (example).

cc @Drup

@hhugo
Copy link
Member

hhugo commented May 13, 2019

What would you expect the following to do ?

let f x =
  object%js (self)
    val z = x [@@jsoo.optdef]
  end

@jchavarri
Copy link
Contributor Author

@hhugo I don't think the current behavior of [@@jsoo.optdef] is totally unexpected, but I was hoping to have a way for the property to not be included in the resulting literal if the value is undefined.

So in the snippet you shared, calling f Js.undefined would return an empty object {}.

@jchavarri
Copy link
Contributor Author

In case it helps, this is the part of the BuckleScript codebase where the external ... = "" [@@bs.obj] case is handled.

Here's the documentation for it.

As you can see, it walks through the args of the external declaration, and then calls Ffi_obj_create. The functionality provided by external + [@@bs.obj] has been extremely helpful in my experience, as it allows to create these literals with optional properties in a very ergonomic way using function labels.

I know this kind of design with annotations for externals is not common in jsoo... but I thought it'd be worth mentioning for more context.

@hhugo
Copy link
Member

hhugo commented May 13, 2019

I'm not against the idea. What do you expect the generated javascript to be. Creating an empty object and and have a bunch of if-then to set fields if not undefined?

@jchavarri
Copy link
Contributor Author

This is a sample implementation I did using the existing APIs:

let optInj prop opt =
  match opt with
  | Some (s) -> [|(prop, Js.Unsafe.inject s)|]
  | None  -> [||]

let create ?x:(x : string option)  ?y:(y : int option)  ?z:(z : int option) () =
  optInj "x" x
  |> Array.append (optInj "y" y)
  |> Array.append (optInj "z" z)

let obj = Js.Unsafe.obj (create ~x:"2" ~y:2 ()) (* {x: "2", y: 2} *)
let obj2 = Js.Unsafe.obj (create ()) (* {} *)

@jchavarri
Copy link
Contributor Author

What do you expect the generated javascript to be. Creating an empty object and and have a bunch of if-then to set fields if not undefined?

@hhugo Yes, in the same vein as this.

As a side question, I'm not sure how BuckleScript does it but it inlines most of the usages. I guess this is an optimization that already exists in the OCaml compiler, right?

@xguerin
Copy link

xguerin commented Nov 6, 2020

Was there any action taken as a result of this question? I would find that capability quite useful.

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

3 participants