Hacker News new | ask | show | jobs
by orangeeater 2724 days ago
> Js barely even supports reflection. This is a huge underrated shortcoming of js if you're doing anything complicated

Can you explain what Java offers with regard to reflection that JS doesn't?

My feeling is that reflection is almost moot in JS since you can inspect/mutate objects at runtime however you like. But maybe I'm missing the point of reflection.

There is a Reflect object with a bunch of static methods on it in ES6. It mostly just replicates functonality that already exists in the language, and my suspicion is that it's mainly there so it can be extended at a later date without breaking backwards compatiblity.

6 comments

> Can you explain what Java offers with regard to reflection that JS doesn't?

Among hundreds of other things, getting the return type of a method and getting the input parameter names (+ types) in a way that doesn't revolve around literally parsing the functions toString() representation.

Oh, and typeof checking that isn't disgustingly broken.

> getting the return type of a method and getting the input parameter names (+ types)

Type information literally doesn't exist at runtime, though. Isn't it kind of ridiculous to compare languages like that?

When you're comparing the relative power of reflection within the language, absolutely not.
But what would you use that information for, given that the language has no types? A JS function has no guarantees of what type a function returns anyway. It's like taking issue with the fact that a car doesn't come equipped with skis.
It's like taking issue with the fact that a car doesn't come equipped with skis.

To draw out that analogy... we live in Greenland. Cars with skis are surprisingly useful.

> Type information literally doesn't exist at runtime, though.

Correct if I'm wrong, not all types get erased in Java. Doesn't type erasure only happen for generics? Say I have a non generic, plain Java class and want to inspect one of it's method's return types at runtime to see if it returns class A or class B. I can do that, right?

Yes, you are correct. There are also a number of circumstances in which you can get generic type info - it isn't erased, for example, if you create a concrete subclass of a generic type.
I was talking about JavaScript. In JavaScript there are no typed functions or arguments, so that information doesn't exist period.
Right, so I guess I'm not understanding your point about why comparing two languages like this is ridiculous. Java has a full blown runtime reflection system (it's "types exist at runtime"). JS doesn't. So Java wins in the reflection category.
But in JS, reflection is pretty much not needed... I don't need to use reflection to see if an object has a quack method, or that I call it with the right types... I just call instance.quack() ... It's up to you as the developer to keep your interfaces and composition in line.

It's actually WAY easier than with C# or Java. Since the use-case of reflection itself is largely unnecessary.

> Among hundreds of other things, getting the return type of a method and getting the input parameter names (+ types) in a way that doesn't revolve around literally parsing the functions toString() representation.

Ah, that's quite cool.

You can do almost anything with Java reflection, JS really pales in comparison.

Which in some ways is a good thing as you can do a lot more optimizations.

Typeof is a good one, but holy crap I had no idea return type and param support was that horrific
Java uses reflection and annotations to support all kinds of language extensions. Js has a lot of nasty issues with the "prototype chain" and annotation support is still experimental. For example, in java, scanning your classes and their annotations to generate code for them at compile time is a standardized feature.

Maybe I'm just complaining that JS is too dynamic, but being able to generate code at compile time with reflection and know it will generally work (type checked) is nice.

Do you have any concrete example for "For example, in java, scanning your classes and their annotations to generate code for them at compile time is a standardized feature"?

Tip: in JS, I don't want OOP class. If you really want class, could you show me the intention behind it?

In general this what java annotation processors are all about. As a specific example, Dagger, a compile time, type safe dependency injection framework. https://google.github.io/dagger/
Java only works in classes :) . They're actually the compilation unit as well so no way around it. (Files are compiled a .class file at a time from single source files)

Adding another example, JPA MetaModel generator that allows you to make strongly typed calls in ORM.

Basically, it let's you generate code at compile time that's seamlessly integrated into the existing code. So it's generated code that still gives you IDE autocomplete support etc.

Every popular ORM uses reflection to determine how to map fields to columns. For example, what type of date or money object to use.

I automagically map some postgres JSONB columns to a parsed object form. Looks just like a regular typed nested object.

That's a solution looking for a problem in JS. You're thinking in types instead of in terms of a dynamic language.

You basically HAVE to do this in Java otherwise your program won't work. In JS, you can look everything over at runtime and dispatch from there (made much easier because first-class functions and closures are a thing).

you can look everything over at runtime

Correct, that's what you have to do in dynamic languages - look at what came in from the database and manually validate+convert it into the format you actually want. Also with pretty much every other form of input (JSON bodies, form posts, queue messages, etc). It's a lot of tedium.

When working with node/python/ruby, I often find myself wishing I could just declare a type and be assured that "the system" will get it right instead of me having to code it out myself. You know, like Java.

Well-written Java programs are generally more concise and less verbose than well-written JS/Python/Ruby programs. Which is to say, when programmers actually validate input instead of (ahem node) crashing the process and dropping all inflight connections when someone submits a json body missing an expected field.

BTW absolutely nothing prevents you from building Java apps by declaring everything as Map<String, Object>. Nobody does that because it's a horrible way to program.

> Well-written Java programs are generally more concise and less verbose than well-written JS/Python/Ruby programs.

This isn't at all true. I can say this from experience using statically typed Python extensively, in an average code base, 80% of your functions, if not more, are already statically correct in Python, one just need add an annotation. Then you're just as "well written" as the Java.

With or without the annotations, the code is still just as "correct".

> BTW absolutely nothing prevents you from building Java apps by declaring everything as Map<String, Object>. Nobody does that because it's a horrible way to program

Yes, but only because you'd need to explicitly cast things everywhere and write out declarations everywhere. If you could always elide casts and type defs, it becomes a lot less horrible.

> Correct, that's what you have to do in dynamic languages - look at what came in from the database and manually validate+convert it into the format you actually want.

You still have to do this in static languages. Maybe a library does it for you, and it gives your an error or something you know is a DbRecordFieldStream or whatever, but dynamic languages can do the same thing. Orms validate input in dynamic languages too. Rails and Django can validate request formats. Protobufs work in every language.

Why do I need to manually convert anything? Even then...

    var results = (await sql.query`
      ...
    `).recordsets[0].map(rowToObject);
It's really easy... no need for complicated ORM/ODM tooling at all.

As far as the size... create a docker container from node:10-alpine to run a given node application, and create a similar container with any application running full Java. And compare the final size.

You should have a look at typeorm [1]. Typescript ORM with decorator support.

1: http://typeorm.io/

That's cool, and will keep it in mind for the next time I work on a node project.

Looks like it works by having the typescript compiler generate experimental annotations in the output javascript, and reading it using a polyfill for the proposed ES7 reflection api. On one hand, yeay looks like proper runtime reflection is coming! On the other hand, it doesn't sound fully baked yet... <insert here a general grumble about how everything in the JS ecosystem is in this state>

Retrofit is another example: https://square.github.io/retrofit/
http://immutables.github.io/ makes great use of this feature in Java
One example would be a url router for a web server that turns the url variables into the handler's expected argument type and ignores requests that do not.

    router.get('/users/:id', (id: UUID) => ...)
    router.get('/products/:id', (id: Int) => ...)
That would be relatively easy to do something very similar with middleware for express/koa

    router.get('/users/:id'. skipNonUuid(id => ...))
You simply have a function/middleware that does the check.... or `compose(skipNonUuid, dbo.findUserById, ui.formatView('modelName'))`

You can do function composition that is nearly as simple and far more flexible in general with JS

Just to be clear, Reflect exists to be direct interface to JS's Module Object Protocol (MOP). Every "primitive" operation you can perform on an object in js, (such as adding a property or getting the value of a property), is exposed via Reflect.
There's no easy way to inspect the runtime in js to find all functions or all classes that can be loaded/called.

There's no way to hook into the loading of modules in a standard way - you have to know how the modules are compiled and required.

> Can you explain what Java offers with regard to reflection that JS doesn't?

One thing comes to mind, how to twinkle stuff inside closures?