Hacker News new | ask | show | jobs
by hackrmn 59 days ago
The article states, quoting:

"JavaScript's module system — introduced in 2015, thirty-two years after Ada's — provides import and export but no mechanism for a type to have a specification whose representation is hidden from importers."

Then:

"in Ada, the implementation of a private type is not merely inaccessible, it is syntactically absent from the client's view of the world."

Am I missing something -- a JavaScript module is perfectly able to declare a private element by simply not exporting it, accomplishing what the author prescribes to Ada as "is not merely inaccessible, it is syntactically absent from the client's view of the world"? Same would go for some of the other language author somewhat carelessly lumps together with JavaScript.

I loved the article, and I have always had curiosity about Ada -- beyond some of the more modern languages in fact -- but I just don't see where Ada separates interface from implementation in a manner that's distinctly better or different from e.g. JavaScript modules.

2 comments

Assuming we’re talking about TypeScript here, because JavaScript doesn’t have exportable types… Any instance in JavaScript, whether or not its type is exported, is just an object like any other, that any other module is free to enumerate and mess with once it receives it. In Ada there are no operations on an instance of a private type except the ones provided by the source module.

In other words, if module X returns a value x of unexported type T to module Y, code in module Y is free to do x.foo = 42.

* only if `x` is _an object_ (read: has methods)

To preempt the obvious: yes, I know _everything_ (nearly) in JavaScript is an object, but a module exporting a `Function` can expect the caller to use the function, not enumerate it for methods. And the function can use a declaration in the module that wasn't exported, with the caller none the wiser about it.

I think you're confusing values with types. JS modules can certainly keep a value private, but there's no way for them to expose an opaque type, because that concept simply doesn't exist in JS. The language only has a few types, and you don't get to make more of them. TypeScript adds a lot of type mechanism on top, but because it's restricted to being strippable from the actual JS code, it doesn't fundamentally change that.
Here's an opaque type wrapping numbers, in JavaScript:

    class Age {
        #value;
        constructor(value) {
            if(typeof value != "number") throw new Error("Not a number");
            this.#value = value;
        }
    }
That field is opaque, but the entire type isn’t, no matter what you do. E.g.,

    let x = new Age();
    x.notSoOpaque = 42;
    console.log(x.notSoOpaque);
We can all agree to layer conventions on top of the language so we just don’t do stuff that violates the opacity. But the same is true of assembly language.
Assigning to `notSoOpaque` (or any other) property on an object in this case doesn't modify its behaviour, because the property isn't structurally part of the interface -- there's no code defined by the creator / owner of the object (e.g. through the class) that uses it. So it doesn't violate the contract. Private fields are inaccessible, everything else is accessible and is thus part of the interface. I am not saying (and never did) this is the same level as Ada, but your example looks contrived to me -- I don't get the relevance.
To expect is different from it being impossible.
Can't argue with that.

But in defence of JavaScript -- since it enjoys routine bashing, not always undeserved -- it now has true runtime-enforced private members (the syntax is prefixing the name with `#`, strictly as part of an ES6 class declaration), but yeah -- this doesn't invalidate the statement "kind of got there 32 years after Ada, stumbling over itself".

JavaScript has supported real data hiding since the beginning using closures. You define your object in a function. The function's local variables act as the private members of the object. They are accessible to all the methods but completely inaccessible to consumers of the object.
I completely forgot about closures. Frankly, they're still my go-to method for encapsulation, in part because the Java-isation of JavaScript done with the private class members and the onslaught of the "Alan Kay's ideas meet Simula" OOP flavour, is relatively new and I am still unsure whether it's a critical thing to have in JavaScript.
See my comment here for an example: https://news.ycombinator.com/item?id=47810686