Is it possible to compile Kotlin Native without runtime checks? - kotlin

I couldn't find a list of compiler flags for the Kotlin compiler. I wanted to know if it is possible to compile Kotlin Native to "unsafe" code without Null check Range checks for arrays etc' in order to create code with less runtime overhead?
It is especially relevant for real-time systems. Is that a valid use case for Kotlin?

Related

What does "Symbol" mean in KSP

Currently I am studying on KSP(Kotlin Symbol Processing), and I am curious about what does "Symbol" mean in KSP.
When it comes to comparing with KAPT, it says "To run Java annotation processors unmodified, KAPT compiles Kotlin code into Java stubs that retain information that Java annotation processors care about. To create these stubs, KAPT needs to resolve all symbols in the Kotlin program."
I don't know what does "all symbols in the Kotlin program" exactly mean?
I understand "symbols" as declarations of interfaces, classes, functions, properties, etc. It doesn't include the body or the code itself, only the API, items that are visible to others.
This term is not specific to Kotlin. I can't find any definition of "symbols" on Wikipedia, but for example native libraries also contain symbol tables.
In this specific context it means that KAPT has to create a full list of all such symbols in Kotlin code and generate their equivalents in Java, so annotation processors could work on them. This is pretty wasteful as we recreate Kotlin code structure in Java just to throw it away seconds later and replace with true compiled code.

Why strip() is deprecated in Kotlin and what should I use instead?

For String.strip() I get warning 'strip(): String!' is deprecated. This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version"
Why is it? "strip" comes from Java String
What should I use?
First of all: String.strip() is a new function in Java 11. Kotlin targets JVM 6 by default, so I was unable to reproduce your issue at first, I got a compilation error. Using JVM 11 as target in Android Studio worked with your compiler warning.
Kotlin's string class (kotlin.String) is not the same as Java's string class (java.lang.String). The Kotlin type is however mapped to the Java type (quote):
Kotlin types such as List, MutableList, String, CharSequence etc. are all compiled to their java equivalents, and thus any runtime checks will not be able to distinguish between them. At compile-time, however, they are distinct types with different sets of members. In particular, the Kotlin types do not have all members that the corresponding Java types have. They have those listed in the Kotlin std lib reference, as well as a few extra JVM specific ones (such as Collection.stream())
kotlin.String does not have a .strip() function. You are just "incidentally" calling java.lang.String.strip() which happens to be there in some target JVMs but not defined in Kotlin. If you look at the kotlin.String source in your IDE you can see it is not defined there.
The reason it is not there is because it was explicitly graylisted by the Kotlin team:
Some methods in JDK classes are undesirable in Kotlin built-ins (e.g. a lot of String methods or List.sort(), because there are Kotlin analogues with better signatures already defined).
.strip() does the same thing as kotlin.String.trim(), so use that instead.
Extended Reading
Extended Reading 2
The commit which put .strip() on the graylist

How is Dart "sound null-safety" different from Kotlin null safety?

This Dart official video states that Dart's so-called "sound null safety" is better than Kotlin's null safety design, because it can optimise the code based on whether a variable is declared nullable, and other languages (I assume this refers to languages including Kotlin) have to do runtime checks to ensure null safety.
So, what extra optimization does Dart do?
How does it interoperate with legacy codebases that are not null-safe (written before null safety) while ensuring null safety?
Dart sound null safety
So, what extra optimization does Dart do?
The benefit of sound null safety in Dart is that the compiler can make use of a non-nullable type, which can elimate null checks. Therefore, the compiler will generate fewer instructions (which results in smaller binaries and faster runtime).
Example
Take the following function:
int getAge(Animal a) {
return a.age;
}
These are the instructions the compiler generated before sound null safety:
As you can see, there are explicit instructions for checking null in the compiled code.
And this is what the same function looks like compiled with sound null safety:
Now, these additional instructions are no longer needed.
Note that the actual instructions generated starting with Dart 2.12 for the example function are the following (there were further optimizations):
See Dart and the performance benefits of sound types by Vijay Menon (Engineering Lead, Dart) for reference.
Interoperability with legacy Dart code bases
How does it interoperate with legacy codebases that are not null-safe (written before null safety) while ensuring null safety?
It does not.
Well, that is not the whole truth. If you want to use Dart >=2.12.0 with any codebase that was written before Dart 2.12 (and with that before null safety), you cannot make use of sound null safety. You can, however, interoperate with these legacy codebases by passing a compiler flag that disables sound null safety. That would be --no-sound-null-safety (see my previous answer for more details).
This means that all benefits of sound null safety are lost when interacting with legacy codebases. This is also why the Dart team encourages all package authors to migrate their code to null safety.
Comparison to Kotlin
Kotlin simply does not have the additional compiler optimizations that Dart achieves with unboxed values thanks to sound null safety.
Keep in mind that Kotlin always allows interoperability with Java, which does not have any concept of null safety. I would imagine that this is a reason why Kotlin will never be able to have sound null safety in the same way that Dart code that interoperates with legacy codebases does not. That is as long as Kotlin code is compiled for the JVM with Java interoperability.
NNBD
If we are not concerned about the compiled code but only about the developer experience, Kotlin and Dart handle null safety identically. That is both languages are non-nullable by default (NNBD).
This means that when writing code in Dart 2.12+ or in Kotlin, all types are assumed to be non-nullable unless you explicitly mark them as nullable.
The only way to get a null pointer exception is by programmer error in both languages, i.e. using the bang operator ! in Dart and double bang operator in Kotlin !!, i.e. a not-null assertion by the developer.
Note that when using null assertions, additional runtime checks have to be added to the compiled code to preserve soundness in Dart. These checks always exists for Kotlin code compiled for the JVM as it is not sound to begin with.
This can also happen when interoperating with Java code when using Kotlin or interoperating with legacy code when using Dart.
There are some more edge cases, see Null safety in Kotlin and Understanding null safety in Dart for reference.
So, what extra optimization does Dart do?
The most basic kind of optimization is that when performing calculations on numeric types, compiler can treat them (internally) as primitive types of non-reference types (unboxed values).
Why is that?
Because they cannot be null and, therefore, it is not necessary to use them as data of referenced types (boxed values).
Why is that?
Because null is represented in Dart as a null constant reference.
If there is no need to refer to this constant, then why not use value types instead of reference type? At least in the generated code, which can be optimized already at compile time.
All this thanks to the so-called "strong mode".
The strong mode in conjunction with non-nullable types allows you to optimize the code already at the compilation stage, which is very important for modes such as AOT, which do not allow code to be optimized at runtime, because it is in the RE (read and execute) mode.
How does it interoperate with legacy codebases that null-safety is not supported while ensuring null safety?
It seems to me that you should ask this as a separate question.

Is C++/CLI an extension of Standard ISO C++?

Is Microsofts C++/CLI built on top of the C++ Standard (C++98 or C++11) or is it only "similar" and has deviations?
Or, specifically, is every ISO standard conforming C++ program (either C++98 or C++11), also a conforming C++/CLI program?
Note: I interpret the Wikipedia article above only comparing C++/CLI to MC++, not to ISO Standard C++.
Sure, it is an extension to C++03 and can compile any compliant C++03 program that doesn't conflict with the added keywords. The only thing it doesn't support are some of the Microsoft extensions to C++, the kind that are fundamentally incompatible with managed code execution like __fastcall and __try. MC++ was their first attempt at it, kept compatible by prefixing all added keywords with underscores. The syntax was rather forced and not well received by their customers, C++/CLI dropped the practice and has a much more intuitive syntax. Stanley Lippman of C++ Primer fame was heavily involved btw.
The compiler can be switched between managed and native code generation on-the-fly with #pragma managed, the product is a .NET mixed-mode assembly that contains both MSIL and native machine code. The MSIL produced from native C++ source is not exactly equivalent to the kind produced by, say, the C# or VB.NET compilers. It doesn't magically become verifiable and doesn't get the garbage collector love, you can corrupt the heap or blow the stack just as easily. And no optimizer love either, the MSIL gets translated to machine code at runtime and is optimized just like normal managed code with the time restrictions inherent in a jitter. Getting too much native C++ code translated to MSIL is a very common mistake, the compiler hides it too well.
C++/CLI is notable for introducing syntax that got later adopted into C++11. Like nullptr, override, final and enum class. Bit of a problem, actually, it begat __nullptr to be able to distinguish between a managed and a native null pointer. They never found a great solution for enum class, you have to declare it public to get a managed enum type. Some C++11 extensions work, few beyond the ones it already had, auto is fine but no lambda expressions, quite a loss in .NET programming. The language has been frozen since 2005.
The C++/CX language extension is notable as well, one that makes writing C++ code for Store and Phone apps palatable. The syntax resembles C++/CLI a great deal, including the ref class and hats in the syntax. But with objects allocated with ref new instead of gcnew, the latter would have been too misleading. Otherwise very different from C++/CLI at runtime, you get pure native code out of C++/CX. The language extension hides the COM interop code that's underneath, automatically reference-counting objects, translating error codes into exceptions and mapping generics. The resemblance to C++/CLI syntax is no accident, they basically perform the same role. Mapping C++-like syntax to a foreign type system.
CLI is a set of extensions for standard C++. CLI has full support of standard C++ and adds something more. So every C++ program will compile with enabled CLI, except you are using a CLI reserved word and this is the weakness of the extension, because it does not respect the double underscore rule for extensions (such reserved words has to begin with __).
You can deactivate those extensions in the GUI by:
Configuration Properties -> General -> Common Language Runtime Support
Even Bjarne Stroustrup calls CLI an extension:
On the difficult and controversial question of what the CLI binding/extensions to C++ is to be called, I prefer C++/CLI as a shorthand for "The CLI extensions to ISO C++". Keeping C++ as part of the name reminds people what is the base language and will help keep C++ a proper subset of C++ with the C++/CLI extension
Language extensions could always be called deviations from the standard, because it will not compile with a compiler without CLI support (e.g. the ^ pointer).

Converting c++ project to clr safe project

I need to work on converting a very huge c++ project to clr safe. The current c++ project has a lot of stuff from c++ like templates, generics, pointers, storage/stream, ole apis, zlib compression apis, inlines etc. Where can I find the datiled document for this type of conversion? Can you suggest some good book to refer to? If anyone of you have done such conversion, can I get some analysis from you?
I'll just cough up the MSDN Library article titled "How to: Migrate to /clr:safe
Visual C++ can generate verifiable components with using /clr:safe, which causes the compiler to generate errors for each non-verifiable code construct.
The following issues generate verifiability errors:
Native types. Even if it isn't used, the declaration of native classes, structures, pointers, or arrays will prevent compilation.
Global variables
Function calls into any unmanaged library, including common language runtime function calls
A verifiable function cannot contain a static_cast Operator for down-casting. The static_cast operator can be used for casting between primitive types, but for down-casting, safe_cast or a C-Style cast (which is implemented as a safe_cast) must be used.
A verifiable function cannot contain a reinterpret_cast operator (or any C-style cast equivalent).
A verifiable function cannot perform arithmetic on an interior_ptr. It may only assign to it and dereference it.
A verifiable function can only throw or catch pointers to reference types, so value types must be boxed before throwing.
A verifiable function can only call verifiable functions (such that calls to the common language runtime are not allowed, include AtEntry/AtExit, and so global constructors are disallowed).
A verifiable class cannot use Explicit.
If building an EXE, a main function cannot declare any parameters, so GetCommandLineArgs must be used to retrieve command-line arguments.
Making a non-virtual call to a virtual function.
Also, the following keywords cannot be used in verifiable code:
unmanaged and pack pragmas
naked and align __declspec modifiers
__asm
__based
__try and __except
I reckon that will keep you busy for a while. There is no magic wand to wave to turn native C++ into verifiable code. Are you sure this is worth the investment?
The vast majority of native C++ is entirely valid C++/CLI, including templates, inlines, etc, except the CLR STL is rather slow compared to the BCL. Also, native C++ doesn't have generics, only templates.
The reality of compiling as C++/CLI is to check the switch and push compile, and wait for it to throw errors.
Rewriting native C++ into safe C++/CLI will result in a code that is syntactically different, but semantically same as C#. If that is the case, why not rewrite directly in C#?
If you want to avoid what is essentially a complete rewrite, consider the following alternatives:
P/Invoke. Unfortunately, I'm unfamiliar whether this would isolate safe from unsafe code. Even if it can perform the isolation, you'll need to wrap your existing C++ code into procedural, C-like API, so it can be consumed by P/Invoke. On a plus side, unless your API is excessively chatty, you get to keep (most of) your native performance.
Wrapping your C++ into out-of-process COM server and using COM Interop to consume it from the manged code. This way, your managed code is completely protected from any corruption that might happen at C++ end and can remain "safe". The downside is a performance hit that you'll get for out-of-process marshaling and the implementation effort you'll need to expend to correctly implement the COM.