Hacker News new | past | comments | ask | show | jobs | submit login

What's the point of such a "declarative" API?

  const localHeader = Struct('localHeader')
    .field('header', DoubleWord(0x04034b50))
    .field('sharedHeaderInfo', sharedHeaderInfo)
    .field('filename', filename);
There's already a construct for key-value pairs in JS, it's called an object:

  const localHeader = Struct('localHeader', {
    'header': DoubleWord(0x04034b50),
    'sharedHeaderInfo': sharedHeaderInfo,
    'filename': filename
  });



Although this is only a handful of lines [0] it's nice to design things well.

- By providing a 'builder' you add a clear API to the struct object's constructor. It doesn't make any more or fewer claims of capibility than it needs to. By exposing the internal storage you break that level of abstraction.

- Even assuming that the JS object type _is_ ordered, the ADT of the Struct type may be subtly different to the ADT of the object. By coupling the two you may prevent future flexibility.

- To that point, the 'field' method _does_ do something with each invocation (forceEndianess) as it adds it to the internal storage. If you passed in a map object it would still need to traverse each key to do that work, which (knowing JS objects) might make it more complicated.

[0] https://github.com/francisrstokes/construct-js/blob/master/s...


You seem to assume that the passed-in object should also be used as the resulting object. This is false, as they can be decoupled.

In other words, it's still possible to pass in a separate js object instance containing the configuration.

Yet I'm not sure about the whole of your arguments, so I can't tell if it would actually make sense to wrap the default js builder pattern implementation (the javascript object initializer syntax aaaaaaaaaaab refers to).

However, I do method builders often overused in API's where a simple singular builder method combined with builder classes suffice and simplify.


Agreed to an extent. But what if you want to extend the API to include the same field twice (for example). The semantics of the input object would prevent that.

I'm reluctant to spend too much time arguing over a fine point. It could be done one way or the other. I was just addressing aaaaaaaaaaab's question.


Really well put!


since order is important, the underlying storage is probably an array of K/V pairs. Object.entries on a dynamically generated object does not guarantee a particular order


They could have used a Map (introduced in ES6 [1]) which maintains key insertion order. However, I'm not sure whether either the object or map interface would be significantly better or worse than the builder-style the author picked. It just doesn't seem to matter, IMO.

The interface that would be most flexible would probably be a list of alternating key values, e.g. ['fieldname', datastruct(), 'fieldname'] since then you could do all the list things to it.

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


The underlying structure is not the issue, it's the object literal that doesn't have its key order defined (in older standards) and therefore the interface as suggested would be broken.

In practice the order will be maintained in the major engines, but that's still not a good reason to do rely on it.


I think the parent is suggesting taking a map instead of an object as the interface for constructing the Struct objects. Not using it as the underlying structure.


Map wouldn't have really brought a lot of clarity or control. You'd have to specify an array of array-pairs, which is noisy IMO, and then you wouldn't have the benefit of being able to programatically/conditionally add fields.

I might consider a static `Struct.fromMap(name, mapObject)`, but as a complimentary API.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: