soabase / soabase-halva Goto Github PK
View Code? Open in Web Editor NEWIdiomatic Scala ... in Java
Home Page: https://github.com/soabase/soabase-halva/blob/master/README.md
License: Apache License 2.0
Idiomatic Scala ... in Java
Home Page: https://github.com/soabase/soabase-halva/blob/master/README.md
License: Apache License 2.0
Be like Scala - throw MatchError when there isn't a default case and there are no matches.
See http://stackoverflow.com/questions/20748858/pattern-matching-symbol
This shouldn't be hard. Maybe a special kind of Any.
I really like the idea of implementing all the standard scala cases as caseOfXxxx calls of Matcher, eg:
caseOfHeadTail(head, tail, ...)
caseOfNil(...)
caseOfTuple*(a, b, ...)
one for each of the TuplescaseOfSome(a, ...)
optional presentcaseOfNone(...)
optional not presentThat covers 90% of how people construct code in a nice tab-completable way :)
Any<Integer> i = anyInt.define();
Any<Integer> j = anyInt.define();
Any<Integer> from = anyInt.define();
For(i, IntStream.range(1, 3))
.set(() -> from.set(4 - i.val()))
.and(j, () -> Iterable(IntStream.range(from.val(), 3)))
.unit(() -> System.out.println((10 * i.val() + j.val()) + " "));
Produces
java.lang.IllegalArgumentException: No value set for: Any(class java.lang.Integer) value: null
Any.anyHeadAnyTail is not in an obvious place in the code. Move/alias them in Matcher.
(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
import path.UsingThisLikeNamespaceTypes.Stack;
@TypeContainer(suffix="Types", "unsuffix"="")
class UsingThisLikeNamespace {
@TypeAlias interface Stack extends LinkedList<Integer> {}
// Then lots of static or non-static methods that use Stack or case classes or whatever
}
Eg see the State monad example
Halva annotation retentions are currently SOURCE
. They should be RUNTIME
.
I would like to define a case class such as:
@CaseClass(json = true)
public interface JsonTest
{
@JsonProperty("first_name")
String firstName();
@JsonProperty("last_name")
String lastName();
int age();
}
Not sure how much halva wants to expose a dependency on Jackson, in terms of the actual annotation used by the interface.
From @martint
One thing that's not clear is that there seems to be some relationship between the "when"s and the >"and"s, but the linear chaining structure doesn't capture it. E.g., if I'm reading it correctly, the:
.when(() -> author.val().name().startsWith("Ayn"))
.and(year, () -> author.val().years())executes nested within each:
.>and(author, () -> book.val().authors())
It's currently hard to debug for-comp and extraction due to all the indirections. Maybe some debug scaffolding can be added.
In Scala, you can do:
val (a, b) = (1, 2)
It would be nice if Halva supported this.
From @dain
also maybe describe why @CaseClassIgnore is useful... wasn't clear what the problem was
I was a bit confused by the case class documentation - I don't understand the difference between a CaseClass and CaseObject... they look the same in the examples
See http://stackoverflow.com/questions/20748858/pattern-matching-symbol
This shouldn't be hard. Maybe a special kind of Any.
Currently can only type alias interfaces
eg Common concrete cases include String
, LinkedList
, fj.data.List
See http://stackoverflow.com/questions/20748858/pattern-matching-symbol
This shouldn't be hard. Maybe a special kind of Any.
There's a bug which causes Halva annotations not to be interpreted if they're not first. You also see the compiler error: Internal error. Could not find annotation: XXX
@CaseClass
public interface WildCardType
{
List<?> anyList();
}
Generates a bad class that doesn't compile.
It would be convenient to be able to directly define an Any. E.g.
Any.define(...) { return AnyDeclaration.of(...).define(); }
It's possible - we can do it - it will be cool.
E.g. this is not currently possible:
@CaseClass interface Case1_ {String name();}
@CaseClass interface Case2_{Case1 case1();}
You'd have to specify "Case1_" in Case2 and then it wouldn't be the right type, etc.
E.g.
public interface Foo {
String foo();
}
@CaseClass
public interface Bar extends Foo {
String bar();
}
This will generate a case class class that doesn't the field foo
and, thus, won't compile.
It's always easy to convert to a List at the end in the user code, but as soon as you internally Collectors.toList
it you irretrievably lose the laziness.
Guard
and SimplePredicate
can be replaced with Supplier<Boolean>
@dain noticed that the docs assume familiarity with Scala:
So in a couple of places you have "you may need to enable Java Annotation processing in your IDE/build tool" maybe link to instructions if this is a real issue
One of the common uses of type aliasing is to tidy up generics in local code, eg
@TypeAlias Stack extends ConsList<Integer> {}
There's a couple of issues with how that works at the moment:
@TypeAliasesInside
class MyPackage {
@TypeAlias StackAlias extends ConsList<Integer> {}
// My business logic that actually uses `Stack`
}
which would then generate MyPackageAlias
containing Stack
, ie my code in MyPackage
then uses final MyPackageAlias.Stack stack;
(note: I think the default unsuffix/suffix should be reversed for the inner type alias, ie user types StackAlias
and the compiler generates Stack
).
That way all my local type aliases remain local to my package, and the codebase is more compact.
interface StackAlias extends ConsList<Integer> {
//...
// Shouldn't this return StackAlias?
ConstList<Integer> tail();
}
I'm not sure that's the only reason, but one of the consequences of this is that the following code doesn't work:
static Tuple2<Integer, StackAlias> pop(final StackAlias stack) {
final Any<Integer> head = new AnyType<Integer>() {};
final Any<StackAlias> tail = new AnyType<StackAlias>() {};
return Matcher.match(stack)
.caseOf(Any.anyHeadAnyTail(head, tail), () -> Tuple.Tu(head.val(), tail.val()))
.get();
}
You have to replace StackAlias
with ConsList<Integer>
inside the Any
One really annoying thing in J8 is that there's no way of passing up typed exceptions, so if you have a long pipeline of lambdas calling functions that can throw them, you end up having to wrap the nice 1-liners in horrible try/catch routines.
I wrote a bunch of simple utilities to convert lambda to untyped exceptions here (eg): https://github.com/Alex-At-Home/Aleph2/blob/master/aleph2_data_model/src/com/ikanow/aleph2/data_model/utils/Lambdas.java#L64
So eg you'd do forComp(a, Utils.wrap(() -> FileUtils.openFile(...)))
One thing you could do in Halva specifically to help with for comprehensions is provide a similar util throwing an (untyped) LambdaException, and then catch those in the forComp
code and have a Optional<LambdaException> For.pipelineError
/ or make it throw err.getCause()
/ whatever a sensible response to the error would be? (Could specify the policy with like forComp(..).ignoreErrors().etc
or forComp(..).throwOnError().etc
)
(In the general "monadic for" case you could also specify what to do with an error, eg make Optional
become empty
, switch a Validation
to fail
)
Pattern/Extraction is currently loosely typed. Make it strongly typed without (hopefully) losing usability.
Will research how difficult it would be to support https://github.com/ngs-doo/dsl-json as a JSON alternative to Jackson.
According to https://github.com/fabienrenaud/java-json-benchmark dsl-json can be 1.5-2x faster than Jackson but requires Mono during compilation (but not runtime).
Enums have certain advantages over vanilla classes:
It would be a simpler implementation to use an enum instead of a class for CaseObjects
. I did a quick proof of concept and made the following changes:
implements
listequals
and hashCode
static
from method signatures and fieldsBasic unit tests pass. Will try and put together a pull request though it is possible that this change may break existing clients.
And then ConsList<T> extends List<T>, Consable<T>
, and all your internal logic that currently depends on ConsList
can depend on Consable
instead.
This leaves library users free to write their own list implementations (inheriting from Consable
but not List
), important since Java doesn't really have a workable immutable list implementation (but eg Functional Java does, even though it can't be used easily because of its abstract construction, annoying)
(Consable
just needs head
/tail
in your internal logic I think? Doesn't need either Iterable
or concat
?)
Eg say I have
List<T> {
static List<T> from(T... ts) { /*...*/ }
//...
}
and I do
@TypeAlias IntList extends List<Integer>
then I'd probably like to be able to do
IntList il = IntList.from(1, 2, 3);
vs IntList il = IntList.IntList(IntList.from(1, 2, 3));
(You can just ignore anything that doesn't return the aliased type)
Creating tuples via T(1, 2, 3)
might conflict with the convention of using "T" as the standard name of the first generic parameter type.
See http://stackoverflow.com/questions/20748858/pattern-matching-symbol
This shouldn't be hard. Maybe a special kind of Any.
https://docs.jboss.org/hibernate/stable/beanvalidation/api/
http://beanvalidation.org/
It would be useful to support JSR-349 annotations on case classes. Unfortunately, the spec only supports property annotations on JavaBean getter
methods. Halva could apply any supplied annotations on the field.
Ex:
@CaseClass
class Foo {
@NotNull
@Size(min = 8, max = 12)
String type();
}
could generate:
class FooCase {
@NotNull
@Size(min = 8, max = 12)
private final String type;
...
One implementation is to take the property annotations, filter out Jackson
annotations and copy the remaining onto the field definition. See http://fasterxml.github.io/jackson-annotations/javadoc/2.7/com/fasterxml/jackson/annotation/JacksonAnnotation.html:
Meta-annotation (annotations used on other annotations) used for marking all annotations that are part of Jackson package. Can be used for recognizing all Jackson annotations generically, and in future also for passing other generic annotation configuration.
(I think if the Monadic class is itself generic)
Example:
Try to build and it should fail during annotation with an NPE
A previous commit (Alex-At-Home/halva-scalaz-examples@ca2f848) avoids the generic type in the ReaderOptionalForFactory
class (which might also cause errors downstream?), leaving a wildcard in the nested generic - this gives the same error as the non-wildcard version (and also separately involves causes type hell in Java, hence the late hour!)
Add support for javac's "-A" overrides.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.