#Convert dynamic to type with wisp.

1 messages · Page 1 of 1 (latest)

night talon
#

Hey everyone, I was looking at the wisp library and I’m having a hard time understanding how I would map a large JSON object to a Gleam type. For example, if my object has 10 properties, how would that work? I was looking at some of the examples of working with JSON in the repo but I’m not quite getting it.

tacit gorge
#

you'd add the gleam_json package and then use the decode function there combined with a decoder you write with the gleam/dynamic module

night talon
#

So far that makes sense. I think the part I get confused about is how I would write the decoder. I don't entirely understand the decoder api.

tacit gorge
#

yeah its actually a bit difficult to decode things with many properties right now

night talon
#

Ah, I see. I think it would be cool if there was a function that let you compose different parts of the decoding process. Like for instance, you could decode1 on the first property, then pipe that to another decode1 where you specify the second property etc until you've mapped the whole object.

tacit gorge
#

if you dont care about getting more than one error

fn decode_thing(dyn: Dynamic) -> Result(Thing, List(DecodeError)) {
  use a <- result.try(dynamic.field("a", dynamic.int)(dyn))
  use b <- result.try(dynamic.field("b", dynamic.float)(dyn))
  ...

  Ok(Thing(a, b, ...))
}
night talon
#

I might have to play around with this a bit and see if I can come up with something.

tacit gorge
#

its not as ideal because if a fails it wont attempt to decode b so you wont get as many errors as you would if you used decode4 or something, but alas

night talon
#

Yeah, ideally it would try all and collect a giant list of errors. But like all things, a good starting point and improvements can be added later.

tacit gorge
#

we've been trying to come up with an ergonomic solution for arbitrarily-sized decoders that accumulate all the errors for literally years and aren't really succeeding 😦

#

but this is good enough for a lot of cases, i hope it works out for you 💕

night talon
#

Thanks! Yeah, it seems like a tough nut to crack. Not sure how other languages are doing it but I can't imagine it's easy. Came up with a thing that seems okay. It does seem like a lot of boilerplate though.

tacit gorge
#

other languages like elm and f# automatically curry their functions. that means all their multi-argument functions are actually just a sequence of one-argument functions. that feature is particular powerful in this scenario because it unlocks a style of programming called "applicative pipelines", it means you could write that as:

dynamic.succeed(Cat)
|> dynamic.and_map(dynamic.field("name", dynamic.string))
|> dynamic.and_map(...)
|> ...

but we can't do that in gleam, which is why those decode1, decode2, ... functions exist 😦

#

It does seem like a lot of boilerplate though.
on this note though, you get used to it ^.^

#

i find gleam and elm both have a fair share of boilerplate, but its a worthy trade to have languages that are so simple - i'd rather the boilerplate than fancy features that make reading all code more difficult

night talon
#

I love the simplicity of gleam as well and it makes learning it very approachable. Thanks for your help!

night talon
#

It seems like some languages like C# are using runtime reflection to handle this. Does the team have any plans to implement runtime reflection type introspection or are there any existing Elixir/Erlang runtime reflection type libraries that could be leveraged?

grave latch
#

Sorry, how would it be different? Isn't the dynamic module using runtime reflection as well?

tacit gorge
#

We wont be introducing reflection to gleam, no

night talon
grave latch
#

you can go through members of an object and use runtime type information with helpers from the dynamic module to cast values to expected type

night talon
#

Yes, and I think that's what @tacit gorge was showing me in the upper examples. Imagine though that you don't want to have to explicitly create a mapping for every type because the type is already defined by the type declaration. Not sure if I'm explaining well here.

grave latch
#

I think people were thinking of doing code generation for this, to generate decoders for a type

night talon
#

Ah, that would be good too

tacit gorge
grave latch
#

but metaprogramming like this is quite early in Gleam, so people need to experiment more (you're welcome to as well!)

tacit gorge
#

No good designs for metaprogramming have come up and its not very high priority

night talon
#

Yeah, no worries, not trying to cause trouble. I'm just really excited about the language and was a little bummed about this.