Re: Go stand behind him


  • BINNED

    @Gribnit I'm just spurting random tangentially-related knowledge here without checking anything first (:kneeling_warthog:); don't expect any proper relevance to what you're doing without doing the research yourself.


  • Considered Harmful

    @kazitor said in Re: Go stand behind him:

    @Gribnit I'm just spurting random tangentially-related knowledge here without checking anything first (:kneeling_warthog:); don't expect any proper relevance to what you're doing without doing the research yourself.

    Oh, fair enough then. That's a lot of fun and I endorse it. And now that the topic is more than one page there's a proper excuse even.


  • Considered Harmful

    @kazitor Also sometimes, people doing this tell me about a kind of vacuum cleaner I haven't stuck my dick in yet in the programming space.


  • Considered Harmful

    @Gribnit So this JDBC mapping API I am using, it directly supports collection but not map types. So either I can mess with it and take the dependency local on a fork, or I can make weird synthetic wrappers...


  • Considered Harmful

    Went with "weird synthetic wrappers", this kinda seems to work...

    2019-01-03 16:33:13.771  INFO 4868 --- [           main] n.g.p.p.repositories.UserRepositoryTest  : original is {
      "name" : "Joe",
      "contact-methods" : [ {
        "name" : "email",
        "url" : "mailto://joe@sch.mo",
        "params" : {
          "default" : true
        }
      }, {
        "name" : "im",
        "url" : "whateverIm://handle",
        "params" : {
          "default" : true
        }
      }, {
        "name" : "moreim",
        "url" : "bleetr://handleAtNite"
      }, {
        "name" : "poke",
        "url" : "desk://13C43",
        "params" : {
          "default" : true,
          "transit" : "10M"
        }
      } ]
    }
    2019-01-03 16:33:13.793 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO pester_users (user_name) VALUES (?) [Joe]
    2019-01-03 16:33:13.814 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 1
    2019-01-03 16:33:13.816 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO contact_methods (user_id, method_name, url) VALUES (?, ?, ?) [1, email, mailto://joe@sch.mo]
    2019-01-03 16:33:13.817 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 1
    2019-01-03 16:33:13.820 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO contact_method_params (owner_id, param_name, param_value) VALUES (?, ?, ?) [1, default, true]
    2019-01-03 16:33:13.821 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 1
    2019-01-03 16:33:13.821 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO contact_methods (user_id, method_name, url) VALUES (?, ?, ?) [1, im, whateverIm://handle]
    2019-01-03 16:33:13.821 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 2
    2019-01-03 16:33:13.822 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO contact_method_params (owner_id, param_name, param_value) VALUES (?, ?, ?) [2, default, true]
    2019-01-03 16:33:13.822 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 2
    2019-01-03 16:33:13.822 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO contact_methods (user_id, method_name, url) VALUES (?, ?, ?) [1, moreim, bleetr://handleAtNite]
    2019-01-03 16:33:13.822 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 3
    2019-01-03 16:33:13.822 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO contact_methods (user_id, method_name, url) VALUES (?, ?, ?) [1, poke, desk://13C43]
    2019-01-03 16:33:13.823 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 4
    2019-01-03 16:33:13.823 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO contact_method_params (owner_id, param_name, param_value) VALUES (?, ?, ?) [4, default, true]
    2019-01-03 16:33:13.823 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 3
    2019-01-03 16:33:13.823 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : INSERT INTO contact_method_params (owner_id, param_name, param_value) VALUES (?, ?, ?) [4, transit, "10M"]
    2019-01-03 16:33:13.824 TRACE 4868 --- [           main] n.z.b.s.c.r.base.MapperRepository        : we got an ID from the database: 4
    2019-01-03 16:33:13.827  INFO 4868 --- [           main] n.g.p.p.repositories.UserRepositoryTest  : after insert is {
      "id" : 1,
      "name" : "Joe",
      "contact-methods" : [ {
        "id" : 1,
        "user-id" : 1,
        "name" : "email",
        "url" : "mailto://joe@sch.mo",
        "params" : {
          "default" : true
        }
      }, {
        "id" : 2,
        "user-id" : 1,
        "name" : "im",
        "url" : "whateverIm://handle",
        "params" : {
          "default" : true
        }
      }, {
        "id" : 3,
        "user-id" : 1,
        "name" : "moreim",
        "url" : "bleetr://handleAtNite"
      }, {
        "id" : 4,
        "user-id" : 1,
        "name" : "poke",
        "url" : "desk://13C43",
        "params" : {
          "default" : true,
          "transit" : "10M"
        }
      } ]
    }
    2019-01-03 16:33:13.848 TRACE 4868 --- [           main] n.z.b.s.c.mapper.base.JoiningRowMapper   : row is 1
    2019-01-03 16:33:13.849 TRACE 4868 --- [           main] n.z.b.s.c.mapper.base.JoiningRowMapper   : top is UserDefinition(id=1, name=Joe, contactMethods=[])
    2019-01-03 16:33:13.878  INFO 4868 --- [           main] n.g.p.p.repositories.UserRepositoryTest  : read is {
      "id" : 1,
      "name" : "Joe",
      "contact-methods" : [ {
        "id" : 1,
        "user-id" : 1,
        "name" : "email",
        "url" : "mailto://joe@sch.mo",
        "params" : {
          "default" : true
        }
      }, {
        "id" : 2,
        "user-id" : 1,
        "name" : "im",
        "url" : "whateverIm://handle",
        "params" : {
          "default" : true
        }
      }, {
        "id" : 3,
        "user-id" : 1,
        "name" : "moreim",
        "url" : "bleetr://handleAtNite"
      }, {
        "id" : 4,
        "user-id" : 1,
        "name" : "poke",
        "url" : "desk://13C43",
        "params" : {
          "default" : true,
          "transit" : "10M"
        }
      } ]
    }

  • Considered Harmful

    Well, I haven't actually totally stopped working on this since I got a more interesting job: https://gitlab.com/gribnitt/pester


  • Considered Harmful

    @Gribnit You use Lombok and for that you must burn.


  • Considered Harmful

    @pie_flavor said in Re: Go stand behind him:

    @Gribnit You use Lombok and for that you must burn.

    Smells like Java 9 but without all the non-lts of Java 9. Burning happily. Wait till you see the really bad shit.


  • Considered Harmful

    @Gribnit if you use compile time code rewriting, you are The Problem. If you want type inference, use a language that uses it, like Java 9 or C# or Kotlin.


  • Considered Harmful

    @pie_flavor There's aspectJ in here too. Fighting with Lombok given the chance. The dynamic tension in the pom is... significant.

    TIL C++ is The Problem...


  • Considered Harmful

    @Gribnit said in Re: Go stand behind him:

    TIL C++ is The Problem...

    Took you this long?


  • Banned

    @pie_flavor said in Re: Go stand behind him:

    @Gribnit if you use compile time code rewriting, you are The Problem.

    U wot m8?


  • Considered Harmful

    @Gąska Specifically the Java variant. Lombok is the worst offender; things like @SneakyThrows or @Getter.


  • Banned

    @pie_flavor but why's it bad?


  • Considered Harmful

    @Gąska because annotations are supposed to be extra information that stuff can choose to interpret. Behavior can be modified and so forth, but a basic rule of annotations is that your code that compiles with annotation processing enabled shouldn't stop compiling if it's disabled. Java's gone out of its way to make the annotation system lightweight; it's one of the quirks, for example, that an annotation interface not being present at runtime will not cause any errors. Java's not designed for hacks like lombok.val, and it's certainly not designed for hacks like lombok.Getter.


  • Banned

    @pie_flavor said in Re: Go stand behind him:

    @Gąska because annotations are supposed to be extra information that stuff can choose to interpret.

    Are they? I've always seen them as, and seen them used as, the entry points for code generators. Serialization, mixins, GUI data bindings, that sort of thing. If annotations aren't meant to be used like this, then it means two things: annotations are almost useless (almost because you really need to @SuppressWarnings sometimes), and Java desperately needs something like annotations that could be used as entry points for code generators.


  • Discourse touched me in a no-no place

    @Gąska said in Re: Go stand behind him:

    Are they? I've always seen them as, and seen them used as, the entry points for code generators.

    That's one of the purposes (as a side-effect of being ways to make reflection easier). They're used for other things too, such as providing extra directives to the compiler itself (@Override is the classic example of this) and for hanging other build-time tools off (e.g., for documentation); this is a feature of the fact that some annotations are not stored in the built code or are in the build but not in the runtime classes.


  • Considered Harmful

    @Gąska You're missing it. Serialization is done by reflection at runtime. Mixins are done by reflection at runtime. GUI data bindings are done at runtime. What I said is that code that compiles with APT processors should not fail to compile without APT processors. Things like Sponge's @Listener, which is interpreted at runtime, or @Plugin, which adds a file to the JAR root, are very different beasts from things like Lombok's @Getter which compiles into an entire getter method, or even worse @Builder which generates an entire builder class. An example of an acceptable form of code rewriting would be Lombok's @ToString, which creates an override of the toString() method without modifying public API.


  • Banned

    @pie_flavor said in Re: Go stand behind him:

    @Gąska You're missing it. Serialization is done by reflection at runtime.

    That's bad. Not horrible, but bad (mostly because of performance).

    Mixins are done by reflection at runtime.

    That's horrible. Like, actually horrible, worse than not having mixins at all.

    GUI data bindings are done at runtime.

    GUI frameworks have shit design anyway, so whatever.

    What I said is that code that compiles with APT processors should not fail to compile without APT processors.

    But why? There's literally no reason whatsoever to do that. It's like saying that programs using Stream APIs should not fail to compile without Stream APIs present.


  • Discourse touched me in a no-no place

    @Gąska said in Re: Go stand behind him:

    There's literally no reason whatsoever to do that.

    Unless you are willing to constrain yourself to a non-standard toolchain (“non-standard” because additional processing steps are being required), the constraint on “annotations must not change the basic semantics” makes sense.

    You might be willing to make such a constraint if it buys you good things in return, of course.


  • Considered Harmful

    @Gąska said in Re: Go stand behind him:

    @pie_flavor said in Re: Go stand behind him:

    @Gąska You're missing it. Serialization is done by reflection at runtime.

    That's bad. Not horrible, but bad (mostly because of performance).

    Mixins are done by reflection at runtime.

    That's horrible. Like, actually horrible, worse than not having mixins at all.

    What the fuck are you on about? What did you think happened in annotation based serialization / mixin systems? It's not done by gremlins. Maybe it's baked on first use and maybe the annotations are reinterpreted each time but there is absolutely no way to do an annotation based system without reflection.

    What I said is that code that compiles with APT processors should not fail to compile without APT processors.

    But why? There's literally no reason whatsoever to do that. It's like saying that programs using Stream APIs should not fail to compile without Stream APIs present.

    Annotations aren't APIs. As I said, Java went out of its way to make them separate from the API.


  • Discourse touched me in a no-no place

    @pie_flavor said in Re: Go stand behind him:

    Maybe it's baked on first use and maybe the annotations are reinterpreted each time but there is absolutely no way to do an annotation based system without reflection.

    It's also possible to bake it ahead of time as an initial-compilation-related step. That would require that additional step be done during build, but that's not terrible or anything; as long as the build steps are properly described in Maven or Gradle or something like that, it'll all work just fine (and reliably too!). It helps that most IDEs have a pretty good understanding of such build instructions.

    What you don't want is a set of build instructions that includes a manual bit “We send this over to Joe Schmoe in the Pennsyltucky office who does something important with a hand-rolled bit of code and sends the result back the following week” because that is Very Bad.


  • Banned

    @dkf said in Re: Go stand behind him:

    @Gąska said in Re: Go stand behind him:

    There's literally no reason whatsoever to do that.

    Unless you are willing to constrain yourself to a non-standard toolchain (“non-standard” because additional processing steps are being required), the constraint on “annotations must not change the basic semantics” makes sense.

    If you want to constrain yourself to a standard toolchain, just don't use things that don't exist in standard toolchain. Simple as that. With every non-standard feature (or bleeding-edge new standard feature, or old, rarely implemented standard feature), you are in exactly one of two situations: either you need it and can afford ignoring environments that don't support it, or you don't need it or can't afford ignoring those environments. In the first situation, you simply use the feature and ignore other environments. In the second situation, you simply don't use the feature at all. In 2007, if for some reason I couldn't use Boost in my C++ project, I simply didn't use boost::shared_ptr. I rolled my own, or I used raw pointers, but I never wrote code that used Boost whenever it could and used the alternative whenever it couldn't. It just doesn't make sense to do that, since the cost of maintaining two parallel solutions in one project is usually astronomical compared to just picking one or the other.

    The only exception is when you really need the feature but also you really need to work when the feature is missing. But it's a really, really rare situation, mostly related to backwards compatibility, inter-process communication, or some other low-level stuff. It's certainly never worth it if all you want is serialization, or autogenerated implementations of some methods (you have to implement all of them manually anyway, so there's no gain).


  • Banned

    @pie_flavor said in Re: Go stand behind him:

    @Gąska said in Re: Go stand behind him:

    @pie_flavor said in Re: Go stand behind him:

    @Gąska You're missing it. Serialization is done by reflection at runtime.

    That's bad. Not horrible, but bad (mostly because of performance).

    Mixins are done by reflection at runtime.

    That's horrible. Like, actually horrible, worse than not having mixins at all.

    What the fuck are you on about? What did you think happened in annotation based serialization / mixin systems? It's not done by gremlins. Maybe it's baked on first use and maybe the annotations are reinterpreted each time but there is absolutely no way to do an annotation based system without reflection.

    Yes there is? Just move the runtime stuff to compile time. Surely it's not hard to imagine. And from what I understood from your rambling about Lombok, it's certainly possible to do all that at compile time in Java. It even makes more sense to do it at compile time than at runtime, since you can type check all the code and make sure everything actually works before the relevant code path even gets run. Moving to runtime the stuff that defines what kinds of operations your class even supports is huge :doing_it_wrong:.

    Not the first time Java turns out to be huge :doing_it_wrong:.

    What I said is that code that compiles with APT processors should not fail to compile without APT processors.

    But why? There's literally no reason whatsoever to do that. It's like saying that programs using Stream APIs should not fail to compile without Stream APIs present.

    Annotations aren't APIs.

    Do they inform external code what kind of operations can be performed on your class? Then they're API. No matter how much you'll ramble about compile time vs. runtime, about APT processors and lack thereof, it all comes down to this one thing. Does the annotation enable your code to be used by external code? Then it's API.


  • Considered Harmful

    @Gąska said in Re: Go stand behind him:

    @pie_flavor said in Re: Go stand behind him:

    @Gąska said in Re: Go stand behind him:

    @pie_flavor said in Re: Go stand behind him:

    @Gąska You're missing it. Serialization is done by reflection at runtime.

    That's bad. Not horrible, but bad (mostly because of performance).

    Mixins are done by reflection at runtime.

    That's horrible. Like, actually horrible, worse than not having mixins at all.

    What the fuck are you on about? What did you think happened in annotation based serialization / mixin systems? It's not done by gremlins. Maybe it's baked on first use and maybe the annotations are reinterpreted each time but there is absolutely no way to do an annotation based system without reflection.

    Yes there is? Just move the runtime stuff to compile time. Surely it's not hard to imagine. And from what I understood from your rambling about Lombok, it's certainly possible to do all that at compile time in Java. It even makes more sense to do it at compile time than at runtime, since you can type check all the code and make sure everything actually works before the relevant code path even gets run. Moving to runtime the stuff that defines what kinds of operations your class even supports is huge :doing_it_wrong:.

    Not the first time Java turns out to be huge :doing_it_wrong:.

    Again: what are you on about? Example. @Listener goes on a method, and the class that contains it gets registered with the EventManager. Said EventManager figures out that it should wrap the class in an EventListener, and when the listener's invoked, pass the event as the first method argument and various fields inside the event as the remaining arguments. How would you move this to compile-time if, for example, EventListener was not present in the API and the API was supposed to be implementation-agnostic?

    What I said is that code that compiles with APT processors should not fail to compile without APT processors.

    But why? There's literally no reason whatsoever to do that. It's like saying that programs using Stream APIs should not fail to compile without Stream APIs present.

    Annotations aren't APIs.

    Do they inform external code what kind of operations can be performed on your class? Then they're API. No matter how much you'll ramble about compile time vs. runtime, about APT processors and lack thereof, it all comes down to this one thing. Does the annotation enable your code to be used by external code? Then it's API.

    The annotation is not what enables your code to be used by external code. My method labeled @Listener can be called by anything. Any class that wants to can call MyPlugin.instance().onInit(new GameInitializationEvent()). The annotation is additional information that the event manager uses to determine that the method should be called when a GameInitializationEvent is posted. If @Listener was knocked off, it would not affect external code's ability to use the method - it would just be a change in metadata.

    e: Oh yeah, and this ability to dynamically fuck with the AST at compile time is documented but unsupported. It's liable to break any time Oracle feels like it, and in fact Lombok isn't working on Java 9-11 yet.