I have the following method:
operator fun get(key: String): String {
//awesome code
}
I have searched a lot, but I could not find anything which actually helped me understand how to describe the operator in the UML.
i am doing it like that:
+ get(in key: String) : String
I think the in is the right operator in this case right?
The best link I have found so far...:
www.uml-diagrams.org
UML does not have a standard way to declare operations to be operators, but you could define your own stereotype for it:
And then use it like this:
The keyword in is optional. If you don't specify in, out or inout, then the parameter is an input parameter by default. If your operator modifies key (I don't know if Kotlin supports that), then you should use keyword inout.
Related
Where I can find Kotlin String plus method implementation?
When I track who calls String#plus, why Intellij IDEA point to "+" ? If String#plus is equal to "+", how does this implement?
I finally find the answer.
Where I can find Kotlin String plus method implementation?
Here I quote answer of ilya.gorbunov who is the member of JetBrains Team member.
"Currently, navigation to builtin sources may not work as expected in maven/gradle projects.
You can find sources of builtins here kotlin/core/builtins at master·JetBrains/kotlin· GitHub 171.
Note that the ‘native’ part of them do not have implementation bodies, as they are implemented as compiler intrinsics.
If you’re more interested in what they are compiled to, you can inspect the generated bytecode with the “Show Kotlin bytecode” action."
Link is here Browsing source code of kotlin.kotlin_builtins like the .. operator
When I track who calls String#plus, why Intellij IDEA point to "+" ?
If String#plus is equal to "+", how does this implement?
The "+" operator is implemented by "Operator overloading" of Kotlin. When view String.kt source code, you can see the below code.
package kotlin
public class String : Comparable<String>, CharSequence {
companion object {}
/**
* Returns a string obtained by concatenating this string with the string representation of the given [other] object.
*/
#kotlin.internal.IntrinsicConstEvaluation
public operator fun plus(other: Any?): String
// omitting some source code
}
Parameter of String#plus method is Any?, meaning we can use "+" operator concatenate any object after string object. Details of "Operator overloading" you can refer to Operator overloading Kotlin's Doc
To illustrate the following example I created a litte spock test (but it's about groovy itself, not spock):
void "some spock test"() {
given: String value = null
expect: someMethod(value) == 3
}
int someMethod(String s) {
return 3
}
int someMethod(Map s) {
return 5
}
There are two methods who's signatures only differ by the type of the given parameter. I thought that when I give it a null value that is explicitly typed as a string, the string-method will be called.
But that doesn't happen; the test fails, because the map-method is called! Why?
I guess groovy ignores the type and treats all nulls the same. There seems to be some kind of priority of types: When I use Object instead of Map as the parameter type of the wrong-method, its all the same, but when I for instance use Integer, the test succeeds.
But than again: If groovy really ignores the type of nulls, why can the following fix the original test:
expect: someMethod((String) value) == 3
If you read my answer to the question Tim already mentioned you will see that I talk there about runtime types. The static type plays normally no role in this. I also described there how the distance calculation is used and that for null the distance to Object is used to determine the best fitting method. What I did not mention is that you can force method selection by using a cast. Internally Groovy will use a wrapper for the object, that also transports the type. Then the transported type is used instead. But you surely understand, that this means a one additional object creation per method class, which is very inefficient. Thus it is not the standard. In the future Groovy maybe change to include that static type information, but this requires a change to the MOP as well. And that is difficult
I am very new to Xtext/Xtend, therefore apologies in advance if the answer is obvious.
I would like to allow the end-users of my DSL to define a 'filter', that when applied and 'returns' true it means that they want to 'filter out' the given entity of data from consideration.
I want to allow them 2 ways of defining the filter
A) by introspecting the attributes of a given data object and apply basic rules like
if (obj.field1<CURRENT_DATE && obj.field2=="EXPIRED)
{ return true;} else {return false;}
B) by executing a controlled snippet using 'eval' of my host language
In other words, the user would be expected to type into a string/code block a valid
code snippet of the hosting language
I had decided that the easiest way for me support case A) would be to leverage the XBase rules (including expressions/etc)
Therefore I defined filters (mostly copying the ideas from Lorenzo's book)
Filter:
(FilterDSL | FilterCode);
FilterDSL:
'filterDSL' (type=JvmTypeReference)? name=ID
'(' (params+=FullJvmFormalParameter (',' params+=FullJvmFormalParameter)*)? ')'
body=XBlockExpression ;
FilterCode:
'filterCode' (type=JvmTypeReference)? name=ID
'(' (params+=FullJvmFormalParameter (',' params+=FullJvmFormalParameter)*)? ')'
'{'
body=STRING
'}';
Now when trying to implement the Java mapping for my DSL, via the inferrer stub in Xtend -- I am running into multiple problems.
All of them likely indicate that I am missing some fundamental understanding
Problem 1) fl.body is not defined. fl Is of type Filter, not FilterDSL or FilterCode
And I do not understand how to check what type a given instance is of, so that I can access the content of a 'body' feature.
Problem 2) I do not understand where 'body' attribute in the inferrer method is defined and why. Is this part of ECore? (I could not find it)
Problem 3) what's the proper way to allow a user to specify a code block? String seems to be not the right thing as it does not allow multiline
Problem 4) How do I correctly convert a code block into something that is accepted by the 'body' such that it ends up in the generated code.
Problem 5) How do I setup multiple inferrers (as I have more than one thing for which I need the code generated (mostly) by xBase code generator)
Appreciate in advance any suggestions, or pointer to code examples solving similar problems.
As a side observation, Inferrer and its interplay with XBase has sofar been the most confusing and difficult thing to understand.
in general: have a look at the xtend docs at xtend-lang.org
You can do a if (x instanceof Type) or a switch statement with Type guards (see domain model example)
i dont get that question. both your FilterDSL and FilterCode EClasses should have a field+getter/setter named body, FilterCode of type String, FilterDSL of type XBlockExpression. The JvmTypesBuilder add extension methods to JvmOperation called setBody(String) and setBody(XExpression), syntax sugar lets you call body = .... instead of setBody(...)
(btw you can do crtl+click to find out where a thing is defined)
strings are actually multiline
is answered by (2)
you dont need multiple inferrers, you can infer multiple stuff e.g. by calling toClass or toField multiple times for the same input
I have an annotation which adds some methods and default constructor to annotated class.
I have managed to create a gdsl, to enable autocompletion in idea for methods, but I'm stuck with constructor and documentation is very poor.
Does anyone have any ideas, how to do this?
Maybe I could find a solution, in existing gdsl, but I can't remember any Transformation, related to constructors. Maybe you can remind me of any of them.
def objectContext = context(ctype: "java.lang.Object")
contributor(objectContext) {
if (hasAnnotation("com.xseagullx.SomeAnnotation")) {
// Here I want to add constructor's declaration(with empty arg's)
// …
// And then my methods.
method name: 'someMethod', type: 'void', params: [:]
}
}
EDITED: OK, if it's as #jasp say, and there is no DSL construct for declaring Constructors, I'm still asking for a good documentation sources, other than JB's confluence page. Tutorials and other sources. I'm familiar with embedded dsl's for groovy, grails and gradle.
Need smth. more structured, if it's possible.
All function invocations inside of GroovyDSL are just calls to wrappers around internal IDEA's Program Structure Interface (PCI). However it doesn't cover all of PCI's abilities, including default constructors functionality I believe. One of an evidence for that is singletonTransform.gdsl, which is bundled into IDEA from 9 version and describes #Singleton AST transformation. Here is it's code:
contributor(context()) {
if (classType?.hasAnnotation("groovy.lang.Singleton")) {
property name: "instance",
type: classType?.getQualifiedName() ?: "java.lang.Object",
isStatic: true
}
}
As you can see it doesn't change a constructor and it's visibility, so IDEA will autocomplete this invalid code:
#Singleton class Foo {}
def foo = new Foo()
Futhermore GDSL that describes the semantics of GroovyDSL (which is actually the part of /plugins/groovy/resources/standardDsls/metaDsl.gdsl of IDEA sources) doesn't provide any ability for describing of constructors.
In this case I suggest you use newify transformation which allows you to describe targetClass.name method returning created instance.
I know this is a bit old, but I found myself looking for something similar.
The DSL you are looking for is
method params: [:], constructor: true although I don't understand why you'd need it; if a class doesn't declare any constructors doesn't IDEA always suggest the default one?
I would like to be able to use plain java-style implicit/explicit casting instead of asType overrides so that sources written in Java work properly. I've overridden asType on String similarly to the approach suggested in How to overload some Groovy Type conversion for avoiding try/catch of NumberFormatException? like:
oldAsType = String.metaClass.getMetaMethod("asType", [Class] as Class[])
String.metaClass.asType = {Class typ ->
if (Foo.class.isAssignableFrom(typ)) {
Foo.myCast(delegate)
} else {
oldAsType.invoke(delegate,typ)
}
}
I'd like all of these options to work:
// groovy
String barString
Foo foo = barString asType(Foo.class) // asType works but
Foo foo = barString // implicit cast fails
Foo foo = (Foo) barString // explicit cast fails
The latter two fail because groovy is using DefaultTypeTransformation.castToType, which doesn't attempt to invoke new Foo() unless the object to be cast is either one of a slew of special cases or is some sort of Collection type.
Note that the solution Can I override cast operator in Groovy? doesn't solve the issue because the code that is doing the casting is regular Java code that I cannot alter, at least not at the source code level. I'm hoping that there is either a secret hook into casting or a way to override the static castToType method (in a Java class, called by another Java class - which Can you use Groovy meta programming to override a private method on a Java class says is unsupported)... or some other clever approach I haven't thought of.
Edit: The question is about using Java-style casting syntax, essentially to use groovy facilities to add an autoboxing method. Groovy calls this mechanism "casting," for better or worse (see DefaultTypeTransformation.castToType as referenced above). In particular, I have replaced an enum with a resourced class and want to retain JSON serialization. Groovy's JSON package automatically un/marshals enum values of instance members to strings and I'm trying to make the replacement class serialize compatibly with a minimal changes to the source code.
Part of the problem here is you are confusing conversion with casting. Using the "as" operator is not the same thing as imposing a cast. They seem similar, but they serve separate purposes.
Foo foo = (Foo) barString
That doesn't say something like "create a Foo out of barString". That says "Declare a reference named foo, associate the static type Foo with that reference and then point that reference at the object on the heap that the reference barString currently points to.". Unlike languages like C++, Groovy and Java do not allow you to ever get in a situation where a reference points at an object that is of a type that is incompatible with the reference's type. If you ever got into a situation where a Foo reference was pointing to a String on the heap, that would represent a bug in the JVM. It cannot be done. You can come up with ways to create Foo objects out of String objects, but that isn't what the code above is about.
The answer appears to be "no". Absent a rewrite of the DefaultTypeTransformation.castToType to allow for this sort of metaprogramming, the implication is to use another implementation strategy or use a different language.