CIL instruction "isinst <valuetype>" - cil

The ECMA Common Language Infrastructure documentation says this about the CIL "isinst class" instruction:
Correct CIL ensures that class is a valid typeref or typedef or typespec token indicating a class, and
that obj is always either null or an object reference.
This implies that a valuetype is not allowed, right? But mscorlib.dll contains a method System.RuntimeTypeHandle::Equals(object obj) with the following instruction:
IL_0001: isinst System.RuntimeTypeHandle
And System.RuntimeTypeHandle is a valuetype. Can anybody put me right here?

Have a look at the declaration of RuntimeTypeHandle:
.class public sequential ansi serializable sealed beforefieldinit RuntimeTypeHandle
extends System.ValueType
implements System.Runtime.Serialization.ISerializable
Although RuntimeTypeHandle is declared as a struct its representation in CIL is some kind of special class. In other words, you can imagine structs as special classes that inherit from System.ValueType and whose attributes follow a strict order.
With that in mind isinst would be callable with RuntimeTypeHandle. For what I interpret isinst is not limited to reference types at all as long as there is a class representing the type.
Let's say we write in C#:
var i = 4;
var b = i is Int32;
We get a compiler warning
Warning: The given expression is always of the provided ('int') type.
What happens? We assign 4 to i. ibecoms an int. On the next line iis being auto-boxed to its corresponding ReferenceType (class), so that the warning is obvious. We could even write
var b = i is int;
I hope this can contribute to some kind of clearification on this topic.

Related

Why does casting to a generic work without an instance of that type?

I've created 2 kotlin methods: one to check a type and another to cast an object. They look like:
fun Any?.isOfType(type: Class<*>): Boolean{
return type.isInstance(this)
// return `this is T` does NOT work.
}
and
fun <T> Any?.castToType(): T {
return this as T
// Works, albeit with a warning.
}
I've read some posts on generics and erasures, but I can't get over what seems to be a discrepancy.
Why is it that checking for the type of an object cannot be done with generics, but casting to a generic can?
The question is why:
fun <T> Any?.castToType() = this as T // compiles with warning
"hello".castToType<Int>()
"works" but this won't even compile:
fun <T> Any?.isOfType() = this is T // won't compile
"hello".isOfType<Int>()
Actually both don't really work. In both cases the type is erased at runtime. So why does one compile and the other doesn't?
this is T cannot work at runtime since the type of T is unknown and thus the compiler has to reject it.
this as T on the other hand might work:
"hello".castToType<Int>() // no runtime error but NOP
"hello".castToType<Int>().minus(1) // throws ClassCastException
2.0.castToType<Int>().minus(1) // no runtime error, returns 1
In some cases it works, in others it throws an exception. Now every unchecked cast can either succeed or lead to runtime exceptions (with or without generic types) so it makes sense to show a warning instead of a compile error.
Summary
unchecked casts with generic types are no different from unchecked casts without generic types, they are dangerous but a warning is sufficient
type checks with generic types on the other hand are impossible at runtime
Addendum
The official documentation explains type erasure and why is-checks with type arguments can't succeed at runtime:
At runtime, the instances of generic types do not hold any information about their actual type arguments. The type information is said to be erased. For example, the instances of Foo and Foo<Baz?> are erased to just Foo<*>.
Due to the type erasure, there is no general way to check whether an instance of a generic type was created with certain type arguments at runtime, and the compiler prohibits such is-checks such as ints is List or list is T (type parameter)
(https://kotlinlang.org/docs/generics.html#type-erasure)
In my own words: I can't check whether A is B if I don't know what B is. If B is a class I can check against an instance of that class (that's why type.isInstance(this) works) but if B is a generic type, the runtime has no information on it (it was erased by the compiler).
This isn't about casting vs checking; it's about using generics vs class objects.
The second example is generic; it uses T as a type parameter. Unfortunately, because generics are implemented using type erasure, this means that the type isn't available at runtime (because it has been erased, and replaced by the relevant upper bound — Any? in this case). This is why operations such as type checking or casting to a type parameter can be unsafe and give compilation warnings.
The first example, though, doesn't use a type parameter; instead, it uses a parameter which is called type, but is a Class object, representing a particular class. This is a value which is provided at runtime, just like any other method parameter, and so you can call methods such as cast() and isInstance() to handle some type issues at runtime. However, they're closely related to reflection, and have some of the same disadvantages, such as fragility, ugly code, and limited compile-time checks.
(Kotlin code often uses KClass objects instead of Java Class objects, but the principle is the same.)
It may be worth highlighting the difference between class and type, which are related but subtly different. For example, String is both a class and a type, while String? is another type derived from the same class. LinkedList is a class, but not a type (because it needs a type parameter); LinkedList<Int> is a type.
Types can of course be derived from interfaces as well as from classes, e.g. Runnable, or MutableList<Int>.
This is relevant to the question, because generics use type parameters, while Class objects represent classes.

Corda Serialization Whitelist

I was trying to serialized a class (DTO) to be used in send and receive
in flows.My DTO class is not in the same module as flows. I
am getting the below errors
1.With #CordaSerializable annotation , My DTO class is not getting serialized and it is throwing
java.io.NotSerializableException: Class "class com.e_mobility.dto.dashboard.DashboardDTO" is not on the whitelist or annotated with #CordaSerializable
With manual whitelisting like below
class CustomSerializationWhiteList : SerializationWhitelist {
override val whitelist: List<Class<*>> = listOf(DTO::class.java)
}
I am getting this error during runtime
net.corda.core.serialization.internal.MissingSerializerException: Unable to create an object serializer for type class com.e_mobility.dto.dashboard.DashboardDTO:
Mandatory constructor parameters [arg0, arg1, arg2, arg3, arg4, arg5, arg6] are missing from the readable properties []
Either provide getters or readable fields for [arg0, arg1, arg2, arg3, arg4, arg5, arg6], or provide a custom serializer for this type
Please help me to resolve this error. (edited)
As you are creating a custom type, did you check that all the needed requirements are fulfilled in your class? The annotation alone might be not enough. From the related Corda documentation about serialization with custom types:
The class must be compiled with parameter names included in the .class file. This is the default in Kotlin but must be turned on in
Java using the -parameters command line option to javac
The class must be annotated with #CordaSerializable
The declared types of constructor arguments, getters, and setters must be supported, and where generics are used, the generic parameter
must be a supported type, an open wildcard (*), or a bounded wildcard
which is currently widened to an open wildcard
Any superclass must adhere to the same rules, but can be abstract
Object graph cycles are not supported, so an object cannot refer to itself, directly or indirectly

Dlang: why are constructors not inherieted?

Is there a way to not have to repeatidly write this(parent class args) {super(parent class args);} when the arguments are exactly the same?
The code:
class Parent {
string name;
this(string name) {
this.name = name;
}
}
class Child : Parent {
}
unittest {
auto child = new Child("a name");
assert(child.name == "a name");
}
https://run.dlang.io/is/YnnezI
Gives me the compilation error:
Error: class onlineapp.Child cannot implicitly generate a default constructor when base class onlineapp.Parent is missing a default constructor
Java and C# don't inherit constructors either (unless that's changed in the last few years - I don't think C++ allowed it either until c++11), and D follows the same reasoning so you can read more by looking up things about them.
Basically though the reason is that subclasses must have their own unique state - at very least stuff like the vtable even if you don't declare any of your own variables - and thus a unique constructor is required. Otherwise you can have uninitialized members.
And if inheritance went the whole way, since Object has a this(), new AnyClass(); would compile and lead to a lot of invalid objects. (In regular D, if you declare any ctor with arguments, it disables the automatically-generated zero arg one.)
Now, D could in theory do what C++ does and auto-generate other args too... it just doesn't. Probably mostly because that is a relatively new idea in C++ and D's class system is primarily based on Java's older system.
But all that said, let me show you a trick:
this(Args...)(auto ref Args args) { super(args); }
stick that in your subclass and you basically inherit all the parent's constructors in one go. If the super doesn't compile for the given args, neither will this, so it doesn't add random things either. You can overload that with more specific versions if needed too, so it is a reasonable little substitute for a built-in language feature.

Accepting managed struct in C++/CLI both with "hat" operator and without. What is the difference?

I've got a C++/CLI layer that I've been using successfully for a long time. But I just discovered something that makes me think I need to relearn some stuff.
When my C++/CLI functions receive an instance of any managed class, they use the "hat" operator ('^') and when they receive an instance of a managed struct, they do not. I thought this was how I was supposed to write it.
To illustrate as blandly as I can
using Point = System::Windows::Point;
public ref class CppCliClass
{
String^ ReturnText(String^ text) { return text; } // Hat operator for class
Point ReturnStruct(Point pt) { return pt; } // No hat operator for struct
};
I thought this was required. It certainly works. But just today I discovered that CancellationToken is a struct, not a class. My code accepts it with a hat. I thought it was a class when I wrote it. And this code works just fine. My cancellations are honored in the C++/CLI layer.
void DoSomethingWithCancellation(CancellationToken^ token)
{
// Code that uses the token. It works just fine
}
So apparently I can choose either method.
But then what is the difference between passing in a struct by value (as I've done with every other struct type I use, like Point) and by reference (as I'm doing with CancellationToken?). Is there a difference?
^ for reference types and without for value types matches C#, but C++/CLI does give you more flexibility:
Reference type without ^ is called "stack semantics" and automatically tries to call IDisposable::Dispose on the object at the end of the variable's lifetime. It's like a C# using block, except more user-friendly. In particular:
The syntax can be used whether the type implements IDisposable or not. In C#, you can only write a using block if the type can be proved, at compile time, to implement IDisposable. C++/CLI scoped resource management works fine in generic and polymorphic cases, where some of the objects do and some do not implement IDisposable.
The syntax can be used for class members, and automatically implements IDisposable on the containing class. C# using blocks only work on local scopes.
Value types used with ^ are boxed, but with the exact type tracked statically. You'll get errors if a boxed value of a different type is passed in.

C++ CLI error C2228

I'm working on a C++/Cli project, so I defined my struct like this.
ref struct token_t
{
public :
static TokenTypes_t TokenType; ///enum class
static String ^ TokenString; ///enum class
static Keyword_t KeywordID; ///enum class
static int IntVal;
static char CharVal;
static Operator_t OprID; ///enum class
};
I passed an instance of this struct as a function parameter, but when I tried to do something like : token.TokenString.pop_back(); it says :
Error 11 error C2228: left of '.pop_back' must have class/struct/union
Did you declare the struct statics somewhere? From your code it is not apparent if you did that or not. If you did not, then mere struct instantiation would NOT get you static member instantiation. You need to instantiate the static members somewhere. Something like
struct token_t::TokenString = "foo"; (correct the syntax if wrong)
First, a System::String (the String^ you declared) doesn't have a pop_back method. Look it up on MSDN for more info.
Second, you declared it static. You are trying to use it with an instance. That doesn't match. Most likely, you don't want any of that static stuff. Remove it.
You also need to access methods of a XXX^ type with the -> operator as if it were a normal pointer.
You need to use the arrow access operator. Other then that, you seem to use System.String as if it was std::string from the native C++ standard library...
OK, several things:
String^ is a reference type, you need to use -> rather than . when calling methods on it.
There is no method pop_back on the string class.
TokenString is declared static, therefore the proper way to access it is token_t::TokenString. If it's static, it's not associated with a particular instance of the type, only with the type itself.
You've got the type declared as ref struct. This is perfectly valid, but confusing. The ref wins out over the struct, so what you have is the same as ref class. If you want a struct (i.e., a value type, not a reference type), you should say value struct token_t. (value class will give you the same result as value struct, but that's again confusing.)
The proper members of the String class are SubString, and Length. Therefore, the line to remove the last character from the string would be this: token_t::TokenString = token_t::TokenString->SubString(0, token_t::TokenString->Length - 1);