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

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.

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

No branches or pull requests

3 participants