Closed Alex-At-Home closed 8 years ago
In the generated class, the Aliases/Cases, etc. would still be "static" classes, right? i.e. you don't need to instantiate the container class.
I don't know what else I want to do in/with the container class (ie it's not just a container, it's also the namespace for all my logic - that's important because that's what lets me keep the case classes and type aliases "local" in a natural way), so I don't want to restrict what I do with it, all I know is that I want to declare Halva artefacts inside it and have them appear in (eg) MyClassName
+Types
So eg two examples:
So, in the monad example, would the StateExample container extend StateExample? Maybe it should be an option in @TypeContainer
.
The way I'd like to write the actual code looks something like this:
package oh.hai;
import oh.hai.ExampleTypes.Stack;
import static oh.hai.ExampleTypes.Stack.Stack;
import oh.hai.ExampleTypes.Point;
import static oh.hai.ExampleTypes.Point.Point;
//...
@TypeContainer(suffix="Types", unsuffix="")
public class Example {
@TypeAlias(suffix="", unsuffix="Alias") interface StackAlias extends ConsList<Stack> {}
@CaseClass(suffix="", unsuffix="Alias") interface PointAlias { double x(); double y(); }
// Business logic
int main(String[] args) {
// Eg
final Stack s = Stack(List(1, 2, 3));
final Point p = Point(1.0, 1.0);
}
}
So although the code is going into a different class (ExampleTypes vs Example), as a developer everything looks like it's local, someone in a different class can happily declare Stack
to be ArrayList<String>
, etc.
In your example above, the generated class would be ExampleTypes
. So, should all the methods, etc. in Example be copied into ExampleTypes
or should ExampleTypes
extend Example
? What's clumsy is that main() expects the generated types to exist but they won't exist until processing. After processing, main() would have to Reference (or have a static import for) ExampleTypes.Stack or something similar.
Hmm interesting, having used now @TypeContainer
a bit more I see what you mean.
Seems like there are two ways of doing it, neither of which is great:
ExampleTypes_
, containing the "local" data model, and then Example with the logic, importing the generated ExampleTypes
(and not having the definitions local)Example
, hit rebuild, and then go write the logic, which is kinda ugly but not a million miles different from creating the data model in a separate file and hitting rebuild? (and then you get the data model visible locally)I feel like some people are going to prefer 1 and some 2?
(In the latter case, ExampleTypes
doesn't inherit from Example
, it's linked to Example
only by the common name stem)
(Do you ever want to inherit the generated container? It's not like you can use the declared versions of anything anyway, you always use the generated ones, no?)
(Fine to enforce that they have a no-arg constructor if needed)
The use case is that a typical requirement for a type container is enforcing something close to "locality" for the aliases/case classes to the package being used, and forcing the class to be an interface is too restrictive (I think! even with
default
s)So eg
Eg see the State monad example