Problems overloading Groovy comparison operators - groovy

I am building an analytic application using Groovy and require very forgiving math operators regardless of data format. I achieve this through operator overloading, in many cases improving (in my case) on the default Groovy type flexibility. As an example, I need 123.45f + "05" to equal 128.45f. By default Groovy downgrades to String and I get 123.4505.
In most cases my overloading works very well, but not for comparison operators. I've followed a couple of discussions on this, but I'm not getting to an answer and I'm looking for ideas. I recognize that the goal is to overload compareTo() (vs. something like lessThan), but Groovy seems to ignore this and instead attempts its own smart comparison - e.g. DefaultTypeTransformation.compareTo(Object left, Object right), which fails on mixed types.
Unfortunately this is a must have for me, because improperly comparing two values compromises the whole solution and I don't have control over some of the data types being analyzed (e.g. vendor data structures).
For example, I need the following to work:
Float f = 123.45f;
String s = "0300";
Assert.assertTrue( f < s );
I have many permutations of these, but my attempt to overload includes (let's just assume my JavaTypeUtil does what I need if I can get Groovy to call it):
// overloads on startup, trying to catch all cases
Float.metaClass.compareTo = {
Object o -> JavaTypeUtil.compareTo(delegate, o) }
Float.metaClass.compareTo = {
String s -> JavaTypeUtil.compareTo(delegate, s) }
Object.metaClass.compareTo = {
String s -> JavaTypeUtil.compareTo(delegate, s) }
Object.metaClass.compareTo = {
Object o -> JavaTypeUtil.compareTo(delegate, o) }
When I try the above test, none of these are called and instead I get:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Float
at java.lang.Float.compareTo(Float.java:50)
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareToWithEqualityCheck(DefaultTypeTransformation.java:585)
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareTo(DefaultTypeTransformation.java:540)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareTo(ScriptBytecodeAdapter.java:690)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareLessThan(ScriptBytecodeAdapter.java:710)
at com.modelshop.datacore.generator.GroovyMathTests.testMath(GroovyMathTests.groovy:32)
Debugging through I see that the < operator goes right to ScriptBytecodeAdapter.compareLessThan(), and the implementation of that seems to ignore the overloaded compareTo() here:
In DefaultTypeTransformations.java:584 (2.4.3)
if (!equalityCheckOnly || left.getClass().isAssignableFrom(right.getClass())
|| (right.getClass() != Object.class && right.getClass().isAssignableFrom(left.getClass())) //GROOVY-4046
|| (left instanceof GString && right instanceof String)) {
Comparable comparable = (Comparable) left;
return comparable.compareTo(right); // <--- ***
}
In a desperate attempt, I've also tried to overload compareLessThan, but I'm grasping now, I don't know that there's any way to jump in front of the < mapping in Groovy.
Float.metaClass.compareLessThan << {
Object right -> JavaTypeUtil.compareTo(delegate, right) < 0 }
Float.metaClass.compareLessThan << {
String right -> JavaTypeUtil.compareTo(delegate, right) < 0 }
Any thoughts on a work-around? Thanks!

Part of it is you need to include static, like this
Float.metaClass.static.compareTo = { String s -> 0 }
This makes f.compareTo(s) work, but the < operator still won't work. This is a known limitation. The only operators that can be overloaded are mentioned in the documentation. Possibly you could do a custom AST to change all those operators to a compareTo().
But this isn't the whole story. f <=> s also doesn't work, despite <=> delegating to compareTo(). I believe this is because Float doesn't implement Comparable<Object> or Comparable<String>, only Comparable<Float>. Although I'm not sure where exactly in the chain Groovy makes the decision not to use that method, you can see it's not limited to Groovy's math classes. This also doesn't work
Foo.metaClass.compareTo = { String s -> 99 }
new Foo() <=> ''
class Foo implements Comparable<Foo> {
int compareTo(Foo o) {
0
}
}
I think Groovy is doing some pre-parsing validation that's preventing the metaclass stuff from working. Whatever validation it's doing definitely inspects the interfaces implemented, because this fails for a different reason
Foo.metaClass.compareTo = { String s -> 99 }
new Foo() <=> ''
class Foo {
int compareTo(Foo o) {
0
}
}
In both of these examples, replacing <=> with compareTo() works.
This question has been asked a couple times before, but I haven't seen a good explanation for why. You might try asking on the user mailing list. I'm sure Jochen or Cedric would be able to explain why.

I guess the point is that your compareTo closure is expecting an Object; so when you invoke compareTo with a String, your closure doesn't get called at all.
I can only think of the following; being precise when specifying closure input parameter type:
Float.metaClass.compareTo = { Integer n -> aStaticHelperMethod(n) }
Float.metaClass.compareTo = { String s -> aStaticHelperMethod(s) }
Float.metaClass.compareTo = { SomeOtherType o -> aStaticHelperMethod(o) }

Related

Null-safe dereferencing operator for older compilers?

I have an old compiler server (VS 2010), which, obviously, can't compile such instructions:
var result = a?.b()?.c?.d;
Is there alternative I can use? Is it possible to do this through expression tree? For example, like this:
var result = NullSafe(()=> a.b().c.d);
There were quite a few attempts to do this before it became a language feature. It's a bit hard to find the references now, but you can get an idea how it can be done and why it's not that easy.
This snippet for example looks simple:
public static R NullSafe<T, R>(this T obj, Func<T, R> f) where T : class
{
return obj != null ? f(obj) : default(R);
}
You can use it almost like an operator:
deliveryCode = order.NullSafe(o => o.DeliveryCompany).NullSafe(dc => dc.FileArtworkCode);
But it doesn't work with value types. This older snippet uses EqualityComparer :
public static TOut NullSafe<TIn, TOut>(this TIn obj, Func<TIn, TOut> memberAction)
{
//Note we should not use obj != null because it can not test value types and also
//compiler has to lift the type to a nullable type for doing the comparision with null.
return (EqualityComparer<TIn>.Default.Equals(obj, default(TIn)))
? memberAction(obj)
: default(TOut);
}
It will take a bit of digging to find more complete examples. I remember trying methods similar to these way back when until I found a more complete one.
This SO answer to a similar question does away with chaining and allows one to write:
foo.PropagateNulls(x => x.ExtensionMethod().Property.Field.Method());
The implementation is a bit involved though, to say the least.

Short-circuiting in functional Groovy?

"When you've found the treasure, stop digging!"
I'm wanting to use more functional programming in Groovy, and thought rewriting the following method would be good training. It's harder than it looks because Groovy doesn't appear to build short-circuiting into its more functional features.
Here's an imperative function to do the job:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
String shortestUniqueName(String nameToShorten) {
def currentLevel = 1
String shortName = ''
def separator = '/'
while (fullyQualifiedNames.findAll { fqName ->
shortName = nameToShorten.tokenize(separator)[-currentLevel..-1].join(separator)
fqName.endsWith(shortName)
}.size() > 1) {
++currentLevel
}
return shortName
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
It scans a list of fully-qualified filenames and returns the shortest unique form. There are potentially hundreds of fully-qualified names.
As soon as the method finds a short name with only one match, that short name is the right answer, and the iteration can stop. There's no need to scan the rest of the name or do any more expensive list searches.
But turning to a more functional flow in Groovy, neither return nor break can drop you out of the iteration:
return simply returns from the present iteration, not from the whole .each so it doesn't short-circuit.
break isn't allowed outside of a loop, and .each {} and .eachWithIndex {} are not considered loop constructs.
I can't use .find() instead of .findAll() because my program logic requires that I scan all elements of the list, nut just stop at the first.
There are plenty of reasons not to use try..catch blocks, but the best I've read is from here:
Exceptions are basically non-local goto statements with all the
consequences of the latter. Using exceptions for flow control
violates the principle of least astonishment, make programs hard to read
(remember that programs are written for programmers first).
Some of the usual ways around this problem are detailed here including a solution based on a new flavour of .each. This is the closest to a solution I've found so far, but I need to use .eachWithIndex() for my use case (in progress.)
Here's my own poor attempt at a short-circuiting functional solution:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
def shortestUniqueName(String nameToShorten) {
def found = ''
def final separator = '/'
def nameComponents = nameToShorten.tokenize(separator).reverse()
nameComponents.eachWithIndex { String _, int i ->
if (!found) {
def candidate = nameComponents[0..i].reverse().join(separator)
def matches = fullyQualifiedNames.findAll { String fqName ->
fqName.endsWith candidate
}
if (matches.size() == 1) {
found = candidate
}
}
}
return found
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
Please shoot me down if there is a more idiomatic way to short-circuit in Groovy that I haven't thought of. Thank you!
There's probably a cleaner looking (and easier to read) solution, but you can do this sort of thing:
String shortestUniqueName(String nameToShorten) {
// Split the name to shorten, and make a list of all sequential combinations of elements
nameToShorten.split('/').reverse().inject([]) { agg, l ->
if(agg) agg + [agg[-1] + l] else agg << [l]
}
// Starting with the smallest element
.find { elements ->
fullyQualifiedNames.findAll { name ->
name.endsWith(elements.reverse().join('/'))
}.size() == 1
}
?.reverse()
?.join('/')
?: ''
}

Groovy inject without a similar Java 8 reduce

Normally I think of Groovy's inject method as equivalent to Java 8's reduce, but I seem to have hit an unusual situation.
Say I have a POJO (or POGO) called Book
class Book {
int id
String name
}
If I have a collection of books and want to convert them to a map where the keys are the ids and the values are the books, then in Groovy it's easy enough to write:
Map bookMap = books.inject([:]) { map, b ->
map[b.id] = b
map
}
i.e., for each book, add it to the map under the book's id and return the map.
In Java 8, the same operation would take a completely different approach. Either this:
Map<Integer, Book> bookMap = books.stream()
.collect(Collectors.toMap(Book::getId, b -> b));
or, equivalently,
bookMap = books.stream()
.collect(Collectors.toMap(Book::getId, Function.identity()));
the difference being a matter of style.
What I'm wondering, however, is if there is a reduce operation in Java 8 that would be similar to the inject from Groovy. I can't just mimic what I did in Groovy, because in Java 8 the signature for reduce is:
T reduce(T identity, BinaryOperator<T> accumulator)
The BinaryOperator means that both elements of the lambda expression must be of the same type. If it was a BiFunction, I could make the lambda's first argument a HashMap<Integer, Book> and the second argument a Book, but I can't do that with a BinaryOperator. I know there's a three-argument version of reduce, but that doesn't seem to help either.
Am I missing something obvious? Is it just that inject is more general that reduce? Since I already have an idiomatic way of solving the problem in Java, this isn't critical, but I was struck by the differences here.
Yo Ken! :-D
You need the 3 parameter form of reduce, so given:
List<Book> books = Arrays.asList(
new Book(1, "Book One"),
new Book(2, "Tim's memoirs"),
new Book(3, "Harry Potter and the sarcastic cat")
);
You can do:
Map<Integer, Book> reduce = books.stream().reduce(
new HashMap<Integer, Book>(),
(map, value) -> {
map.put(value.id, value);
return map;
},
(a, b) -> {
a.putAll(b);
return a;
}
);
To give:
{
1=Book{id=1, name='Book One'},
2=Book{id=2, name='Tim's memoirs'},
3=Book{id=3, name='Harry Potter and the sarcastic cat'}
}
The first parameter is the thing to collect into:
new HashMap<Integer, Book>(),
The second parameter is a BiFunction that takes the current accumulator, and the next element in the stream, and combines them somehow:
(map, value) -> {
map.put(value.id, value);
return map;
},
The third binary operator in that reduce call:
(a, b) -> {
a.putAll(b);
return a;
}
Is how to join all the resulting maps back together assuming you are running a parallel stream...
put and putAll returning void make it a fugly mess :-( But I guess chaining wasn't a popular thing back in the late 90s...

specifying properties of relations in alloy

I am trying to express certain mathematical properties of relations in Alloy, but I am not sure if I have the right approach yet, as I am just a beginner. Would appreciate any insights from the community of experts out there!
Specifying the fact that domain of a relation as singleton. e.g. Is the following a reasonable and correct way to do that?
pred SingletonDomain(r: univ->univ) {
one ~r
}
sig S2 {}
sig S1 {
child: set S2
}
fact {
SingletonDomain [child]
}
or should it be something like the following
pred SingletonDomain (r: univ->univ) {
#S2.~r = 1
}
This is not very modular since the use of S2 is very specific to the particular signature.
Specifying the fact that a relation is a total order. At the moment I am using the following, basically I am simulating xor
pred total[r: univ->univ] {
all disj e, e': Event | (e.r = e' and e'.r != e) or (e.r != e' and e'.r = e)
}
Thanks
To specify the fact that the domain of a given relation is a singleton, your first attempt is really close to do the trick. The only problem is that one ~r enforces the inverse of the r relation (and thus the r relation itself) to be composed of a single tuple. This is not what you want to express.
What you want to express is that all elements in the range of the r relation have the same (so only one) image through its inverse relation '.
You should thus write the following predicate :
pred SingletonDomain(r: univ->univ) {
one univ.~r
}
For your second question, your predicate doesn't handle cases were e -> e' -> e '' -> e. To handle those, you can use transitive closure.

Use literal operators (eg "and", "or") in Groovy expressions?

My current work project allows user-provided expressions to be evaluated in specific contexts, as a way for them to extend and influence the workflow. These expressions the usual logical ones f. To make it a bit palatable for non-programmers, I'd like to give them the option of using literal operators (e.g. and, or, not instead of &, |, !).
A simple search & replace is not sufficient, as the data might contains those words within quotes and building a parser, while doable, may not be the most elegant and efficient solution.
To make the question clear: is there a way in Groovy to allow the users to write
x > 10 and y = 20 or not z
but have Groovy evaluate it as if it were:
x > 10 && y == 20 || !z
Thank you.
Recent versions of Groovy support Command chains, so it's indeed possible to write this:
compute x > 10 and y == 20 or not(z)
The word "compute" here is arbitrary, but it cannot be omitted, because it's the first "verb" in the command chain. Everything that follows alternates between verb and noun:
compute x > 10 and y == 20 or not(z)
───┬─── ──┬─── ─┬─ ───┬─── ─┬─ ──┬───
verb noun verb noun verb noun
A command chain is compiled like this:
verb(noun).verb(noun).verb(noun)...
so the example above is compiled to:
compute(x > 10).and(y == 20).or(not(z))
There are many ways to implement this. Here is just a quick & dirty proof of concept, that doesn't implement operator precedence, among other things:
class Compute {
private value
Compute(boolean v) { value = v }
def or (boolean w) { value = value || w; this }
def and(boolean w) { value = value && w; this }
String toString() { value }
}
def compute(v) { new Compute(v) }
def not(boolean v) { !v }
You can use command chains by themselves (as top-level statements) or to the right-hand side of an assignment operator (local variable or property assignment), but not inside other expressions.
If you can swap operators like > and = for the facelets-like gt and eq, respectively, i THINK your case may be doable, though it will require a lot of effort:
x gt 10 and y eq 20 or not z
resolves to:
x(gt).10(and).y(eq).20(or).not(z)
And this will be hell to parse.
The way #Brian Henry suggested is the easiest way, though not user-friendly, since it needs the parens and dots.
Well, considering we can swap the operators, you could try to intercept the Integer.call to start expressions. Having the missing properties in a script being resolved to operations can solve your new keywords problem. Then you can build expressions and save them to a list, executing them in the end of the script. It's not finished, but i came along with this:
// the operators that can be used in the script
enum Operation { eq, and, gt, not }
// every unresolved variable here will try to be resolved as an Operation
def propertyMissing(String property) { Operation.find { it.name() == property} }
// a class to contain what should be executed in the end of the script
#groovy.transform.ToString
class Instruction { def left; Operation operation; def right }
// a class to handle the next allowed tokens
class Expression {
Closure handler; Instruction instruction
def methodMissing(String method, args) {
println "method=$method, args=$args"
handler method, args
}
}
// a list to contain the instructions that will need to be parsed
def instructions = []
// the start of the whole mess: an integer will get this called
Integer.metaClass {
call = { Operation op ->
instruction = new Instruction(operation: op, left: delegate)
instructions << instruction
new Expression(
instruction: instruction,
handler:{ String method, args ->
instruction.right = method.toInteger()
println instructions
this
})
}
}
x = 12
y = 19
z = false
x gt 10 and y eq 20 or not z
Which will give an exception, due the not() part not being implemented, but it can build two Instruction objects before failing:
[Instruction(12, gt, 10), Instruction(19, eq, 20)]
Not sure if it is worth it.
The GDK tacks on and() and or() methods to Boolean. If you supplied a method like
Boolean not(Boolean b) {return !b}
you could write something like
(x > 10).and(y == 20).or(not(4 == 1))
I'm not sure that's particularly easy to write, though.

Resources