Is it possible to define a new operator in Groovy? - groovy

Is it possible to define a brand new operator in Groovy? I would like to express a trade where someone buys 200 items for the price of 10 like this:
def trade = 200 # 10
Is this achievable?
Thanks
EDIT: I want to make it clearer that I am interested in defining an operator not adding a method. Cheers.

We always wanted the ability to define an operator through the user in Groovy, but so far we haven't gotten around the problems that come along with that. So the current state is that Groovy does not support custom operators, only the ones that are already in use.

I am not quite sure how you can make this work for the # sign but you could certainly add the operation like this which I actually find more expressive:
Number.metaClass.buyFor { Integer price ->
delegate * price
}
def result = 200.buyFor(10)
println result

Number.metaClass."#" {Integer x -> delegate * x}
assert (2.'#' (2)) == 4

The official documentation has a section on Operator Overloading: https://groovy-lang.org/operators.html#Operator-Overloading
Here is a list from the docs:

Related

Select only a type of object inside a list python

I have a list of 2 types of customers classic customer and hipsters. I have a function associated to these classes which tells me if they are in budget. I would like to know if it still exist a hipster which is in budget.
Something like, however the isinstance() return me a boolean.
any(isinstance(x, HipsterRecurrent).is_in_budget() for x in self.RecurrentCustomersList)
I succeed ! I did any(isinstance(x, HipsterRecurrent) and x.is_in_budget() == True for x in self.RecurrentCustomersList)

Groovy - Set your own property of an Integer

I just started to learn Groovy and wondering if you can set your own property for an integer. For example,
def a = 34.5.plus(34.34)
def b = 5.64.minus(3.43)
def c = 12.64.multiply(33.43)
In the above there are certain methods like plus minus and multiply
What should I do if I want to define some of my own methods for integers like that.
I searched Google but couldn't find much about it.
Sure, you can just add methods to the metaClass of Integer.
Here's an example:
Integer.metaClass.zeds = { -> 'z' * delegate }
assert 3.zeds() == 'zzz'
You can also add methods to a single instance of integer should you wish to, ie:
Integer num = 4
num.metaClass.halved = { -> delegate / 2.0 }
assert num.halved() == 2.0
You can also add methods to classes via Extension Methods a good explanation of which can be found over here
It should be noted (as you originally tagged this question as Java) that obviously, Java code will have no knowledge of these things, as it doesn't know about the metaClass
Use groovy meta programming, this allows you to create dynamic method creation atruntime in the class that you want to place in .
bydefault if a method is not found methodmissing exception throws , this is where groovy allows you add method at runtime for more reference use the below comprehensive link
http://groovy-lang.org/metaprogramming.html
If this answer helps , dont forget to click answered.

Elasticsearch - Using groovy script within function_score and access field payload

I am trying to understand what is the best way to access the payload while using groovy script.
I want to do something like this:
sum = 0;
categories = doc['category'].values;
for (category in categories){
sum += category.payload
}
return sum;
Edit:
Thanks to #Val and #Lee H I got to this point where I can actually access the payloads. But the suggested solution was to use _index which is not what I am looking for, _index give access to statistics in the scope of the index, and not for a specific document.
I want to go over every document, and take its payload and multiply it with some constant lets say.
when doing this: _index['category'].get('term', _PAYLOADS) I will get a list of all payloads of "term", which will is not what I am looking for.
So is there a way to access a field payload from the scope of a document?
Check out the documentation for
term positions and payloads
it shows an example accessing the payloads for a field
Copying the last example here:
Example: sums up all payloads for the term foo.
termInfo = _index['my_field'].get('foo',_PAYLOADS);
score = 0;
for (pos in termInfo) {
score = score + pos.payloadAsInt(0);
}
return score;
You can achieve this using advanced scripting and the _index context variable.
And Groovy is here to help with a nice one-liner:
return _index['category'].get('term', _PAYLOADS).sum {it.payloadAsInt(0)}

How to convert Rep[T] to T in slick 3.0?

I used a code, generated from slick code generator.
My table has more than 22 columns, hence it uses HList
It generates 1 type and 1 function:
type AccountRow
def AccountRow(uuid: java.util.UUID, providerid: String, email: Option[String], ...):AccountRow
How do I write compiled insert code from generated code?
I tried this:
val insertAccountQueryCompiled = {
def q(uuid:Rep[UUID], providerId:Rep[String], email:Rep[Option[String]], ...) = Account += AccountRow(uuid, providerId, email, ...)
Compiled(q _)
}
I need to convert Rep[T] to T for AccountRow function to work. How do I do that?
Thank you
;TLDR; Not possible
Explanation
There are two levels of abstraction in Slick: Querys and DBIOActions.
When you're dealing with Querys, you have to access your schema definitions, and rows, Reps and, basically, it's very constrained as it's the closest level of abstraction to the actual DB you're using. A Rep refers to an hypothetical value in the database, not in your program.
Then you have DBIOActions, which are the next level... not just some definition of a query, but the execution of it. You usually get DBIOActions when getting information out of a query, like with the result method or (TADAN!) when inserting rows.
Inserts and Updates are not queries and so what you're trying to do is not possible. You're dealing with DBIOAction (the += method), and Query stuff (the Rep types). The only way to get a Rep inside a DBIOAction is by executing a Query and obtaining a DBIOAction and then composing both Actions using flatMap or for comprehensions (which is the same).

Can I redefine String#length?

I'd like to re-implement a method of a Java class. For example, for "hi".length() to return 4. (How) Can I do that?
I know using SomeClass.metaClass I can get a reference to an existing method and define new (or overriding) method, but I can't seem to be able to do that for existing Java methods.
Using Groovy, you can replace any method (even those of final classes) with your own implementation. Method replacement in Groovy uses the meta-object protocol, not inheritance.
Here's the example you requested, i.e. how to make String.length() always return 4
// Redefine the method
String.metaClass.invokeMethod = { name, args ->
def metaMethod = delegate.metaClass.getMetaMethod(name, args)
def result = metaMethod.invoke(delegate, args)
name == 'length' ? 4 : result
}
// Test it
assert "i_do_not_have_4_chars".length() == 4
Seems like it could be possible by abusing String metaClass. But the attempt I've done so far in groovy console didn't led to the expected result :
def oldLength = String.metaClass.length
String.metaClass.length = { ->
return oldLength+10;
}
println "hi".length()
outputs the sad 2
I think you could take a look at Proxy MetaClass or Delegating metaClass.
If you did redefine it, it would only work in Groovy code. Groovy can't change the way Java code executes.
In Groovy, "hi".length() is roughly equivalent to this Java:
stringMetaClass.invokeMethod("hi","length");
Because Groovy doesn't actually call length directly, metaClass tricks work in Groovy code. But Java doesn't know about MetaClasses, so there is no way to make this work.
Although this question is very old I like to point out another way (at least for newer Groovy versions) .
The length() method in java.lang.String is implemented from java.lang.CharSequence interface. In order to reimplement the method using the String-metaClass you need to "override" the method in the metaClass of the interface first.
CharSequence.metaClass.length = { -> -1}
String.metaClass.length = { -> 4 }
assert "i_do_not_have_4_chars".length() == 4
The solution using String.metaClass.invokeMethod changes the behaviour of all String-methods and is problematic. For instance, simply invoking "asdf".size() leads to an exception on my setup.

Resources