In Groovy you can do surprising type conversions using either the as operator or the asType method. Examples include
Short s = new Integer(6) as Short
List collection = new HashSet().asType(List)
I'm surprised that I can convert from an Integer to a Short and from a Set to a List, because there is no "is a" relationship between these types, although they do share a common ancestor.
For example, the following code is equivalent to the Integer/Short example in terms of the
relationship between the types involved in the conversion
class Parent {}
class Child1 extends Parent {}
class Child2 extends Parent {}
def c = new Child1() as Child2
But of course this example fails. What exactly are the type conversion rules behind the as operator and the asType method?
I believe the default asType behaviour can be found in: org.codehaus.groovy.runtime.DefaultGroovyMethods.java
org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.java.
Starting from DefaultGroovyMethods it is quite easy to follow the behavior of asType for a specific object type and requested type combination.
According to what Ruben has already pointed out the end result of:
Set collection = new HashSet().asType(List)
is
Set collection = new ArrayList( new HashSet() )
The asType method recognizes you are wanting a List and being the fact HashSet is a Collection, it just uses ArrayList's constructor which takes a Collection.
As for the numbers one, it converts the Integer into a Number, then calls the shortValue method.
I didn't realize there was so much logic in converting references/values like this, my sincere gratitude to Ruben for pointing out the source, I'll be making quite a few blog posts over this topic.
Related
Consider class with type parameter, that should be used as Map key.
class Foo<K> {
var map: Map<K, Dynamic> = new Map();
}
This does not compile with error Type parameters of multi type abstracts must be known.
The reason is understandable - Map is abstract and it's underlying type is selected based on key type, so key type should be known when compiling new Map() expression. On the other hand non-generic type with type parameters are compiled once for all parameters.
Looks like adding #:generic metadata should help. But actually it does not. My guess was that this is because haxe compiler compiles #:generic types the same as it does with non-generic types, and only then does some extra work for generic type. So I was thinking that having a Map with key type defined by type parameter is impossible in haxe.
But recently I've stumbled upon this issue: https://github.com/HaxeFoundation/haxe/issues/2537
Simn's answer there says, that this can be done by adding #:remove #:generic metadata. And it actually works.
#:remove #:generic
class Foo<K> {
var map: Map<K, Dynamic> = new Map();
}
For me this looks like magic and I'm not comfortable with this. In documentation I only see that
#:remove Causes an interface to be removed from all implementing classes before generation. That does not explain why this works.
If you replace Map by haxe.ds.BalancedTree and use only #:generic without #:remove, you will see your class Foo generated on your target containing new BalancedTree< object, object > (object is Dynamic). That means, Foo class holds general BalancedTree< object, object > type, while Foo_String for example holds generic BalancedTree< string, object > type. Now, if you go back to your Map, you will see that "Abstract haxe.ds.Map has no #:to function that accepts haxe.IMap< Foo.K, Dynamic >", e.g. no Map< Dynamic, Dynamic > implementation exists. That's why you need to use #:remove which will actually stop generation of Foo class, or at least, remove new Map< Dynamic, Dynamic > from the Foo (#:remove "Causes an interface to be removed" is misleading here)
I dont know how to describe the problem, so weird. I have function like this:
long getPersonId(...){
//...
}
The above function returns Id of a person based on some arguments.
So I logged the return value of the function and it is 1.
Then I have code like this:
person = myMap.get(getPersonId(..))
which returns null object but this returns a valid Person object, why?:
person = myMap.get(1)
But as I described before getPersonId(..) returns 1, which basically means
myMap.get(getPersonId(..)) == myMap.get(1)
myMap is typed as Map<Long, Person> myMap
What is happening here?
In Groovy, as in Java, 1 is an int literal, not a long, so
myMap.get(1)
is attempting to look up the key Integer.valueOf(1), whereas
myMap.get(getPersonId(..))
is looking up the key Long.valueOf(getPersonId(...)). You need to make sure that when you populate the map you are definitely using Long keys rather than Integer ones, e.g.
myMap.put(1L, somePerson)
In your original version of this question you were calling the GORM get method on a domain class rather than the java.util.Map.get method, and that should work as required as the GORM method call converts the ID to the appropriate type for you before passing it on to Hibernate.
I am so sorry the problem was when I initialize the map myMap
Map<Long, Person> myMap = [1, new Person()]
when you say something like this the key is an integerbut not a long still groovy not complaining.
So the problem is my method was returning a long value (1L) but my actual key on the map is integer value(1).
So changing my map init to Map<Long, Person> myMap = [1L, new Person()] solved the problem.
Probably this due to dynamic nature groovy but irritating unless you know how dynamic langs behave lol.
I have a class which inherit a dictionary.
class SymbolsWithQuotes: Dictionary<string, IList<Quotes>> // ex: key: AAPL value: quotations for the last year
{
// Empty class
}
At first, I think its a good idea to inherit a dictionary for readability but now I have a Linq query where I end the statement by:
ToDictionary(x => x.Key, y => y.Value.ArrayObjects()
.Select(blabla));
And I have no idea how to cast it to my class SymbolsWithQuotes.
So three questions:
1 / Was is it a good idea to inherit a dictionary for readability ?
2 / Is there a solution to cast my linq query to my object SymbolsWithQuotes
3 / Do you see an alternative solution easier to read and to maintain ? Or should I just use Dictionary> everywhere instead of object SymbolsWithQuotes
Thanks
[Edit] I precise that my linq Query does returns a type
Dictionary<string, IList<Quotes>>
If your SymbolsWithQuotes is nothing but an empty class, then I suggest you not use it. As you've seen, it makes things a bit difficult.
If you just want to create an alias for the name, you could use the using directive:
using SymbolsWithQuotes = Dictionary<string, IList<Quotes>>;
Grade in an Enum Structure.
var y=1;
var x= (Grade)y;
I'm trying to do the same thing as the above line but with a dynamic CLASSNAME.
FieldInfo field = typeof(Person).GetField("Grade");
var x= Convert.ChangeType(y ,field.FieldType);
I tried that. this works fine but not for enums.
I think the problem is with the way you are accessing the field on the enum. Enum fields are static. By default, the Type.GetField method uses binding flags equivalent to BindingFlags.Public|BindingFlags.Instance. This won't match an enum member.
If this is the problem you are having, then you can use typeof(Person).GetField("Grade",BindingFlags.Public|BindingFlags.Static) to get the FieldInfo for the field named "Grade" on the enum type named "Person". This assumes that your model looks like:
enum Person
{
Grade
}
There's another problem with your code that is compatible with enums as well. It's not totally obvious because your example seems to treat "Grade" as both a field and an type. If my previous suggestion doesn't describe your model, and the following does, then the problem is that you are using Convert.ChangeType which in this case should give you an InvalidCastException.
You need to find a different way to cast the value to your enum. If the class name is not known at compile-time, then I would suggest using linq expressions, e.g.
Type targetEnumType = typeof(Person).GetField("Grade");
ConstantExpression runtimeValue = Expression.Constant(y);
UnaryExpression cast = Expression.Convert(runtimeValue,targetEnumType);
LambdaExpression lambda = Expression.Lambda(cast);
Delegate getTheCastValue = lambda.Compile();
object value = getTheCastValue.DynamicInvoke();
This code assumes that your model looks something like
class Person
{
public Grade Grade;
}
enum Grade
{
First = 1,
Second = 2
}
However, looking at this, it becomes obvious that if Person is a non-generic class, then you would have to know the type of the Grade field at runtime, so you are better off just doing a (Grade)y cast, like in your example.
I've got a problem here. (C#)
There's a collection in another assembly (I cannot change it) that takes a string as parameter and returns an object.
Like:
object Value = ThatCollection.GetValue("ParameterName");
The problem is, for each parameter string, it returns a DIFFERENT type as object.
What I want is to cast those objects to their respective types, knowing the types only at runtime by their string names.
I need to do some operations with those returned values.
And for that I need to cast them properly in order to access their members and so.
Limitations:
I cannot use "dynamic" since my code needs to be done in an older framework: 3.5 (because of interop issues).
I need to do operations with MANY returned values of different types (no common interfaces nor base classes, except "object", of course)
All I have is a table (containing string values) correlating the parameter names with their returned types.
Yes, I could transform that table into a biiig "switch" statement, not very nice, don't want that.
Any hints??
You want to look into reflection, something like the following should work to cast an object to type T. Set up a simple cast method:
public static T CastToType<T>(object o)
{
return (T)o;
}
Invoke this using reflection:
Type t = Type.GetType(stringName)
MethodInfo castTypeMethod = this.GetType().GetMethod("CastToType").MakeGenericMethod(t);
object castedObject = castTypeMethod .Invoke(null, new object[] { obj });