A subset of an AntColony is another AntColony containing sub-arrays. One element of an AntColony is an Ant which you can instantiate with the data at the appropriate index from each array. I'm not trying to be difficult, I really don't see the problem with implementing these basic programming tasks.
I agree that spelling out the fields can become tedious if you have a lot of structures of arrays or lots of fields per structure. A 100-line Python script can generate all this code for you if you prefer. Sure, it's a "limitation" of most programming languages that they don't provide this out of the box. But not a big limitation, I'd argue. Many languages even have features that allow you to write this functionality as a library, 100% inside the language (Python and Java annotations, for example).
> I really don't see the problem with implementing these basic programming tasks.
That you have to write them over and over again for every single class. You offer to do that with Python.
> But not a big limitation, I'd argue. Many languages even have features that allow you to write this functionality as a library, 100% inside the language (Python and Java annotations, for example).
This is an argument of the "all languages that are Turing complete are essentially equivalent" kind. True, but not interesting in this context.
Ecosystem matters. If your Java program is the only one that does these things, it may just as well not be Java. You will be unable to use any other library without back-and-force adapters, for example.
> That you have to write them over and over again for every single class. You offer to do that with Python.
Or with some other code generator. A mythical language with SoA/AoS transformation "built in" will do exactly the same under the covers. But it might not offer other features you are used to, or (your argument) a sufficiently rich library ecosystem. You might as well do it yourself and use a language you are otherwise familiar and happy with.
> This is an argument of the "all languages that are Turing complete are essentially equivalent" kind.
Is it? You can't do what I described in C, for instance. To be clear, what I meant when I wrote "as a library, 100% inside the language" was that, given the appropriate definitions in a library, not in an external tool you run before your build, you just write something like the following Python:
class Ant:
someField = ...
someOtherField = ...
@StructureOfArrays
class AntColony:
pass
or something the following Java:
class Ant {
int someField;
boolean someOtherField;
}
@StructureOfArrays
class AntColony {
}
and get all the features you can dream of generated for you inside the AntColony class, which you then use exactly as if you had typed things out yourself. You can't do this in C. This isn't an "all Turing complete languages" argument as far as I can see.
> You will be unable to use any other library without back-and-force adapters, for example.
I don't understand what you mean. In the above example, the Ant class exists, so you don't need adapters. The arrays inside the AntColony class exist (once the annotation processor is done with them), so you don't need adapters.
> You might as well do it yourself and use a language you are otherwise familiar and happy with.
Nim, Rust, D, Lisp support this already as compiled languages, without sacrificing anything - perhaps also Zig - at the macro level. Jai offers it as a language feature, but I don't think that's a particularly good idea - it's just that Jai tries to stay simple in such a way that doesn't let it be a user-level thing.
> Is it? You can't do what I described in C, for instance.
Not exactly, no, but you can with "X-macros", and I have - in fact - been doing that since 2005 or so, using only features from C89 ; I admit I have not used Java in the last 10 years, and then it was impossible - maybe some of the revisions in the last decade made it possible "inside the language" - what's the name of the feature I need to look up?
> I don't understand what you mean. In the above example, the Ant class exists, so you don't need adapters. The arrays inside the AntColony class exist (once the annotation processor is done with them), so you don't need adapters.
And now, you try to use the standard library "Sort" or "Find", it doesn't work without adapters, even if you have comparators defined for Ant -- and many other things that assume that objects are not part of a colony.
It's hard to explain in a short post. I occasionally use a language called "K" of the APL family, which makes all of this incredibly trivial from the get go. It's not a new language - K itself IIRC predates Java by a couple of years, APL (of which K is often considered a dialect) was first specified in 1958 and implemented in 1962. It basically considers everything an array - one or multiple dimensional - and field access is nothing more than having one of the axes specified by symbols rather than numbers. This makes everything incredibly simple and uniform to an extent that is hard to describe to someone who has not experienced it. (And indeed, in the turing sense it makes no difference .... but if you implement your Java objects as "mapping from field to value" you may get some of the benefits but will not really be using Java or be able to use the ecosystem)
I only gave this a passing thought before and was too quick to dismiss it. Yes, I see how it can be done. Which is just another argument that the whole thing is a non-issue, no? Languages with macro systems can do it. Languages with other build time code generation systems can do it as well.
> what's the name of the feature I need to look up?
Annotation processors. Here's the first thing I found with an example of code generation: https://cloudogu.com/en/blog/Java-Annotation-Processors_3-Ge.... Yes, it's considerably more verbose than a macro system. But it's still a tiny, write-once (or completely off-the-shelf) part of your overall project.
> And now, you try to use the standard library "Sort" or "Find", it doesn't work without adapters
OK, but the same is true for all the macro based systems you mentioned above, isn't it? And if it isn't: whatever you can generate with macros you can also generate some other way.
Edit: You won't like this, but looking at the docs for Java's Collections.sort method (https://docs.oracle.com/javase/7/docs/api/java/util/Collecti...: "This implementation dumps the specified list into an array, sorts the array, and iterates over the list resetting each element from the corresponding position in the array." So you can use it just fine if the SoA implements the List interface. But yes, at the cost of temporarily materializing an array of structs.
That what I refer to as the "Turing complete" argument. Yes, you can definitely do all of those. But almost no one does - and those that do, usually silo themselves from the ecosystem.
Yes, if you like Java, you can definitely implement a Java compiler/interpreter in C and get everything you like about Java using C. But no one does.
Thanks for the reference, I'll read about annotation processors later tonight.
I appreciate the discussion, but I believe you're arguing in bad faith.
> Yes, you can definitely do all of those. But almost no one does
<shrug> That's what you say. What is this based on, considering that until a few hours ago you didn't even know that Java has this built-in code generation facility?
When I search for "entity component sytem java", the first hit is this project: https://github.com/Rubentxu/Entitas-Java which uses a "code generator [that] generates classes and methods for you, so you can focus on getting the job done. Radically reduce the amount of code you have to write and improve readability. It makes more of a sea code less prone to errors to ensure the best performance."
Sure, it's probably not as widely used as other frameworks in other languages. Java isn't necessarily the first thing on people's mind when it comes to implementing AAA games.
> and those that do, usually silo themselves from the ecosystem.
You have not shown this. And if you mean that your C macro implementations do this -- fine. But you still seem to find them useful enough to keep using them?
> Yes, if you like Java, you can definitely implement a Java compiler/interpreter in C and get everything you like about Java using C.
That is a Turing equivalence argument. But using a very simple code generator for a very simple problem is not the same thing. Given that Java syntax is very similar to C, I wouldn't be surprised if your existing macros could be used 1:1, with the hardest part being getting a Java build system to call the C preprocessor on a Java file. Not quite the same thing as implementing an interpreter.
(Also, as far as I'm concerned this was never about Java per se.)
I wasn't aware it is now an integrated part of the JDK, but it doesn't change much; I've used ANTLR decades ago (and YACC even more decades ago) which is ... essentially the same thing, except Java has now standardized and simplified it so that you don't need to fiddle with your Ant or Maven or Makefile.
> Sure, it's probably not as widely used as other frameworks in other languages.
I've been doing professional work for over 30 years now, so I think I have some perspective, which may of course be different than yours. Code generators and processors have always had their niches, but that's what they are - niches - and they are quite small.
People used to use YACC, or ANTLR or Bison or Lemon or whatever your favorite parsing tool is. That's because they save an enormous amount of work in most use cases where they are applied. But they also come with great costs: Hard to debug when things go wrong, but most importantly - inflexible. GCC and many, many other projects move off parser generators at some point in their life for flexibility reasons.
Qt has MOC, which was essential in older C++ and is now IIRC optional because modern C++ has mostly caught up. It is widely hated among Qt users, though it did offer significant advantages. But I'm not aware of any project that used MOC except to interface with Qt - the boundary is always evident.
> You have not shown this. And if you mean that your C macro implementations do this -- fine. But you still seem to find them useful enough to keep using them?
How could I "show" this? It is obviously predicated on the projects I've been involved with, which - I noted - have not been Java in the last ten years. It's not like it's something that can be "shown", except in some statistical sense, the validity of which we will argue forever.
And yes, people shy away from macro heavy C code (whenever J source code or A source code gets posted on HN, people are less than happy, e.g. https://news.ycombinator.com/item?id=8533843 ; the whole J system looks like that ).
I use macro heavy code only when I don't have to share it with others, for that reason.
> But using a very simple code generator for a very simple problem is not the same thing.
Well, perhaps we're not thinking of the same level of simple - e.g. c++ template meta programming, which I first used in 1995 is built in, and (literally) turing complete, so it can do anything, but is far from "simple" - not to actually write, not to use, and definitely not to debug.
What I had in mind was things like https://github.com/Hirrolot/poica - It uses C macros to do incredible magic. All it needs is one #include and it gives C introspection, oop and a few other things. Is it simple? I wouldn't say that. But more importantly, is it C ? I wouldn't say that, and so does the guy who made it. It can be used in a C program, yes. It can e.g. go further and define comparators for you so you can use qsort() on the new types it helps you define. But it's not really C because when you try to integrate it with an existing C codebase, you'll find that you keep having to translate things at every boundary - which is quite likely to happen with a Java SoA library.
I think my point is that languages in common use (Java, C, C#, ...), despite offering the facilities to locally solve the issues described in the original article (locality of reference mostly), they do not practically allow these solutions to become widespread or common because they are not part of the core, and as a result you lose all benefits on library boundaries.
I agree that spelling out the fields can become tedious if you have a lot of structures of arrays or lots of fields per structure. A 100-line Python script can generate all this code for you if you prefer. Sure, it's a "limitation" of most programming languages that they don't provide this out of the box. But not a big limitation, I'd argue. Many languages even have features that allow you to write this functionality as a library, 100% inside the language (Python and Java annotations, for example).