Tag Archives: c#

Starting over with errors

Current state

It didn’t take me long to realize I simply hate working with Option type as a replacement of exceptions — instead of simply writing the code I have to babysit each possible failing function and write conditions for each optional value (I am not the only one in pain). So I read again about Java, C#, Haskell, OCaml and Rust (did you notice Rust team introduced subtle flaw in design — in Haskell and OCaml the correct outcome of the function is the right outcome. In Rust it is on the left, so the right answer is the erroneous answer). I can sum this up as follows:

  • C# approach is a dead end because it leads to duplicating functions — dreadful Do and TryDo pattern,
  • Java annotated functions with exceptions that can be thrown and passed was a mistake, it only takes few minutes of writing the code to feel tired. And for unchecked exceptions it shares the same problem as C#,
  • Haskell looked promising until I saw the real code tackling the errors — so partially I would be in camp I want to escape from already (Skila), and partially in heavy function annotating camp which I dislike since my Java experience. Also I am sceptical how smooth this solution is when it comes to inheritance and when you read “Error handling” chapter (from Real World Haskell by Bryan O’Sullivan, John Goerzen, Don Stewart) you might get the impression that something is fishy, if one feature kills another feature and you need to jump extra hoops to use both.

I have wrong design (more in artistic sense) and three approaches which, well, I don’t like.

I could agree with the sentence “if you don’t have anything right to say, or anything that moves the art forward, then you’d better just be completely silent and neutral, as opposed to trying to lay out a framework” (from interview with Anders Hejlsberg) but not in this case — working on and implementing the language which is broken from start is no fun, and has no value at all. I must make a second, third — fourth if necessary — try to find out the solution. After all it has to be somewhere.

Envisioned design

Skila will have exceptions but they will be thrown usually by code injected by compiler. All errors in computations should be signalled by:

  • optional value — if it is likely that user will handle the error. It is counterpart of function that requires its outcome to be read. As an example consider String.indexOf — not finding character in string could lead to an error, but it is rather not an error by itself,
  • Error type — here the situation is reversed, it is more likely that the “client” would treat an error like a serious computation failure and pass it for handling to some upper function, it is counterpart of the function that allows its outcome to be ignored. Every unhandled error is automatically converted to exception. Error type will be subtype of any other type, so returning an Error instead of “real” value does not need to (and cannot?) be annotated in function signature. In other words every function can fail.

You can convert optional value to exception (this is already done), you can convert error to exception or to optional value. The beauty I foresee is present in several aspects:

  • it is transparent to inheritance,
  • it should not clash with any other feature,
  • single function will be enough,
  • the flow of the errors is layered,
  • no extra code necessary — you want to cope with errors, you do it, you don‘t want to — simply behave naturally (as with exceptions).

What is layered flow of errors? By default, the function you talk directly to could give you an error, but all third party functions involved in computation can result in exception (because every unhandled error becomes an exception). You could depict such propagation in default flow:

deep function ⟶ nearby function ⟶ your function
  (error)      |                  |
               |     (error)      |
               |   (exception)    |
               |                  |   (exception)

In the first line you see deep function returns an error. The error is passed to the nearby function (line 2), since it is incoming error and it is unhandled it becomes an exception (line 3), it is then “passed” to your function. In more real life perspective, when you call for example dict[key] (nearby function) for non existing key you will get error and you can handle the error right away. But if the failure is caused because there is a some logging (deep function) involved, and that logging failed, you will get an exception, not an error.

Again, this is the default flow — every function can handle the values it gets and convert them to whatever necessary.

Problems

Entire mechanism is very similar to passing null in C# — in Skila it will be done on purpose, as a bait. But there is difference — in C# you can pass null without triggering exception, in Skila even passing has to be checked. This is for easier finding the source of the error and also to consistently process all the functions including those which work for their side effects (all Void functions are prime examples). So performance can be a victim here.

Advertisement
Tagged , , , , , ,

Counting the infinite sequences

Doesn’t it strike you as odd, that you can write such code in C#:

if (sequence.Any()) ...

and it is efficient as it can be, but when you rely on Count method:

if (sequence.Count() > 0) ...

you may fall into a trap of extensive computation despite you just need confirmation whether the sequence is empty or not. Well, this disparity annoyed me for a long time and all I could think of was passing somehow a predicate to Count. It is as fishy as it sounds, and it annoyed me even more.

Until the perspective changed — who said Count should count anything? Why Count should jump right away with exact answer?

Count should be lazy and it should simply return the instance of some numeric like type, say SequenceCount — that type should keep reference to the sequence, have implicit conversion to Int and — what is crucial — it should also overload comparison operators. With all those goodies you could finally write:

// Skila syntax
if (1...).count() > 0 then 
  stdOut.writeLine("not empty");
end

to see a printout after a few CPU cycles.

Now when I solved this issue I can think of general lazy evaluation design for Skila…

Tagged , , , ,

Generic static fields — see you next year

I wanted to make a mental note at the end of 2015 — “feature freeze”. It won’t happen, I cannot make my mind what is the right choice.

The natural decision would be to copycat C# — each constructed type has its own copy of static fields which allows to use generic static fields. Resharper wiki warns about this approach — “in the vast majority of cases, having a static field in a generic type is a sign of an error” ¹. We can find simpler one in Java (more for historical reasons than technical, but still) — it does not support generic static fields and it shares static fields among all constructed types. Scala takes another angle for the same model — since static data can live only in companion objects and they cannot have type parameters the issue is solved by design. As for Swift it is an open question because as the error message says static fields are “not yet supported in generic types”.

C# has some peculiarities — till now I didn’t figure out why C# makes instances of static constructor (see Accelerated C# 2010 by Trey Nash, p.263). Skila would have to add its own because of static variables in generic methods. I feel really insecure here so I wonder whether C# model is worth the effort?

A memento from C++ world:

The original intention of C++ template support envisioned a use-directed automatic instantiation mechanism that required neither user intervention nor multiple instantiations of the same file. This has proved considerably more difficult to achieve than anyone at the time imagined (see [STROUP94]).

— Stanley B.Lippman, Inside the C++ Object Model

Sure, it is not the same issue, over 22 years passed, nevertheless I still have the chills. Until I have firm knowledge or burning desire for this feature I’d better follow Swift footsteps — not supported. Yet.


¹ I was curious what “vast majority” means so I contacted the author of that entry, Dmitri Nesteruk. As it turned out it doesn’t translate to any numbers, it was just a generalization based on the nature of C# model.

Tagged , , , , , , , , , ,

Into the valley of nulls

Working on the new design of null brought so many challenges that I didn’t implement any special support for them in generic types — the concept is pretty alien to me and I don’t know what to fix because nothing is broken yet.

Skila features stackable null values with no performance penalty compared to regular values. It means indexOf for String does not use magic value -1 any longer, the pair first/firstOrDefault of the collection is the pattern of the past. All you need to return is optional value.

You can work with optional values safely:

let i ?Int = null;
test(i); // compile error

def test(i Int) Void ...

Can you guess why you will get compile error? Type mismatch? Close, but not enough — types do match here but conditionally (there is precisely one level of Option<T> difference) and this means the entire call is executed conditionally as well. Statement became expression with the outcome failure or success which has to be read or explicitly dropped. Like here:

let i ?Int = null;
_ = test(i); 

def test(i Int) Void ...

For the record there is no magic here, just regular error:

let i ??Int = null;
test(i); // classic type mismatch

def test(i Int) Void ...

There was no need to introduce special syntax for optional chaining (besides there would be asymmetry between optional caller and optional argument), so instead of clunky “?.” you write:

var s ?String = null;
s = s.toLower(); 

which is equivalent of:

var s ?String = null;
s = s is null ? null : s'value.toLower(); 

Unlike pre-6.0 C# no exception is thrown, unlike C# 6.0 the syntax is clear, and unlike Icon you cannot simply ignore the optional execution. Time will tell whether such approach is indeed a winner.

Tagged , , , ,

The object initialization

Writing constructors by hand is so tedious that I am happy C# has object initializers. Well, sort of happy, because they are not really object initializers (they are just member assignments) and because of that they often collide with the configuration of the members (private or readonly). One thing I cannot deny — they offer really compact form of setting up the object:

new Point() { X = 5.3, Y = 7.2 };

Scala and Kotlin address the same problem providing also compact form, true initialization, however in not very pleasing manner:

class Point(var x: Double, 
            var y: Double) 
{
  ...
}

Without such constructor the structure of type definition is pretty clear, with constructor added all of the sudden part of the type is moved as parameters, so it looks like a method which is, and which is not at the same time. Different taste I assume.

Let’s write bare type Point in Skila:

class Point
  var x = Double(13.2);
  var y Double;
end

Some things worth noting — both fields are private by default, you cannot omit the typename unless you initialize the field (or property) with constructor, which is the case here. Type inference is useful feature to have but it is best served in moderate ratios.

Our Point type has default constructor, but we cannot initialize Point object with custom values. Let’s change it:

class Point
  in var x = Double(13.2);
  in var y Double;
end

And that’s it — the keyword in says ”add named parameter to constructor and initialize the given field with it”. In other words such constructor is added behind the scenes:

  def init(x : Double = 13.2, y : Double)
    this.x = x;
    this.y = y;
  end

Because of the named parameters (note the colon) the compiler can add default values wherever it wants. Named parameters also mean user has to provide the names:

Point(x : 3, y : 15.5);
Point(y : 7, x : 1); // the order does not matter
Point(y : 1.5);
Point(2, 3.5); // error, no names
Point(x : 2); // error, missing `y` parameter

What can I say — I honestly like this design. It is as clear as C# code, but you don’t lose any benefit of real constructor. What’s more, you can use in keyword as a parameter and an argument as well:

base class Animal
  in let weight Double;
end

class Human : Animal
  in let iq Double;
  let label String;

  def init(label String = "Joe", in)
    super(in); // calling base constructor
    this.label = label;
  end
end

// `label` is anonymous parameter
Human("Jane",iq:130,weight:60); 

The only requirement is in parameter has to come last, it is small price to pay if you ask me.

Tagged , , , , ,

Leaving the trenches of the Option<T> type

Please note currently Skila has only reference types (not that it is well thought over decision, I simply don’t have enough time to deal with value types).

The problem how to return data from the function efficiently while fitting in special “no result” value, haunts me for some time. I am aware of several approaches:

  1. magic values, like -1 for indices (it is still used, see Go),
  2. thin Nullable<T> type to mark there is no result (you can see this in Kotlin),
  3. rich Option<T> type for wrapping the actual value (Swift, Scala approach),
  4. Try-Parse pattern (for sure it is used in C# libraries).

The first approach is dead simple and fast, yet it is disaster when it comes to serious programming — each time you have to check what magic value you can get. The second approach is much better but it does not scale very well — you can use it for a substring lookup, but it fails with dictionary getter or such functions as first on collection. Yet, the performance is on par with magic values.

For me the only realistic answers are the last two — with Option<T> type you can work with any function, you just add an extra layer of Option<T> to the working type. The performance suffers but you always have fast counterpart functions tryDoSomething. Of course some poor soul has to write all those pairs of functions now — because of that I was seriously considering supporting two types at the same time, lightweight Nullable<T> and rich Option<T>.

Oh yes, there is another approach:

  1. communicate failure (like in Icon),

I have no idea what the performance is, but the Icon code is simply beautiful. It was about time to read a book about it — I barely even opened The Implementation of the Icon Programming Language by Ralph E. Griswold and Madge T. Griswold when I found this inspiring passage:

(…) the design of programming languages should not be overly inhibited by perceived implementation problems, since new implementation techniques often can be devised to solve such problems effectively and efficiently.

I am sold — I want beauty, and I want performance! Nothing less. I want stackable (nested) Option<T> type, easy to use with speed of raw null values. Until now I was focusing on optimizing nested Option<T> type, but maybe I could somehow add a stack to null… wait a second.

Let’s consider what happens on the first nesting level (think of Option<T>) — we have either the actual value or a null. On the second level (Option<Option<T>>) — the actual value or a null again. At both levels when we have the actual value we can recognize that we didn’t end up with no result because our reference is not equal to null. It is the null which has to be wrapped (because null from the first level of nesting plays a role of true data on the second level), the real, actual value does not need any wrapping. It is some progress but we still have to do a little wrapping, right? No, we don’t — just turn the microscope on and take a look. In the first case the failure is indicated by null¹, in the second case by another, different nullnull².

Click, click, click — do you hear this sound?

Option<T> type. Who said it is a regular type in the first place? It does not have to be — our Option<Option<T>> is a disjoint union of types. It is Null² type, or Null¹ type, or T type — Null²|Null¹|T.

Because we have to tell compiler what type we would like to get, it knows at what level it operates — i.e. how many layers it should pretend unwrapping to get the value. If it is any of the null value cases, it will also know how long it should pretend it has real data — the show with single null keyword is just for the user. Say the pointer is set to null¹ and our current type is Option<Option<String>> — do we have real value? Sure thing, it is not null² and that’s all we have to care about.

Thanks to all those lies there is no wrapping values in the runtime, the speed is the same as working with plain old null values. The only difference comparing to rich Option<T> school is with down casting — we will be able to tell what type we hold in hand (String for example), but we will not be able to deduce what union of types it comes from (Null¹|String or maybe Null²|Null¹|String).

Could it be this cookie is absolutely for free? Unfortunately — no. Union types does not work well with generic types (at least if you want to keep static control over types), but since we have here very specific case of union we can enrich type info with option counter. Whenever there is Option<T> type used we have to take option counter from type T and increment it.

This leaves me a syntax to think about and supporting three valued logic to consider — this could add an interesting twist to the language.

Tagged , , , , , , , , , , , , ,

What is easy — generics with nullable types not for sure

For a week I have been removing features from Skila (so far just two) and postponing some nice things for later implementation — I still want Skila to look at least nicely. Ironically that easy subset is not that easy to grasp, currently I hit hard on nullable types. So far I could see three camps:

  • C# — implicit null-check with null values (there are no referential non-nullable types though),
  • Kotlin camp — explicit null-check with null values,
  • Swift camp — as Kotlin but with wrapper class “Option” instead of null.

Take my words with grain of salt because I don’t know Kotlin or Swift.

Using “null” is not the same as having “Option”, the second can be wrapped as many times as you like when in case of the former you cannot wrap “null” into “null” — it is a value, not a wrapper.

On the other hand all checks designed for nullable type can be applied to non-nullable type, this is not true with optional types. For example one can blindly execute “x != null” check in Kotlin, while the analogous code in Swift requires “x” to be really an “Option”.

Worse, both Kotlin and Swift approaches bring problems to Skila, for example — how do you initialize objects of generic type? If I choose Kotlin solution how does inheritance tree look like for nullable types? And even if I choose Kotlin approach indeed I know that “Option” type will have to be added as well, so maybe add it right from the beginning… and so on and on.

Just to increase my confusion I found out some inconsistency in Kotlin:

open class Foo {
  fun foo() : Int {
    return 0;
  }
}

fun test<T : Foo?>(x : T) : Int {
  return x.foo() // (*)
}

fun main(args : Array<String>) {
  println(test<Foo?>(null))
} 

Compiler should demand “x!!.foo()” in line marked with “(*)”, but the code above compiles without any errors. And it worries me for Skila — those two ideas (generics with nullable/optional types) are not easy and it is hard to foresee (at least for me) all the problems with writing generic classes in practice.

If you are curious you can play online with both languages — playground for Swift and for Kotlin.

Tagged , , , , , , ,

Don’t mix deferred execution with optional outcome

I prefer using yield when returning IEnumerable because code looks really clean — storing the output manually loses this nice look, not mentioning extra wrapper method.

But the look can be misleading when the language design leaves a hole — and I fell into this trap. I used yield in method that returns not some crucial data, but simply a report about what was not computed. You can read it, display it, or ignore it, your call. The problem is yield unlike cached result, uses deferred execution. And deferment is based on usage of… the outcome. So if you ignore it (and C# compiler does not make a peep about it), it will be not executed at all.

The lesson for C# devs is this — if it is OK to ignore the outcome of the method (as in my case, just a summary of computation), do not use yield. Go with storing the output inside the method.

Tagged , ,

All the things that can bite you…

The summer is rather slow when it comes to development (hopefully we passed 35°C zone) but I am doing good progress with cleaning the code anyway.

One thing that stopped me was C# struct. Most of the time I work with classes and despite I know what the struct is, I simply don’t have vast practice with it, and so I was caught off-guard.

I was implementing Option which should work as Nullable for all types. Since it should express strictly the notion of an option, it has to be a struct (otherwise you would have to deal with missing option, unset option and set option with missing value — tad too much). Implementing it was no brainer, thanks to C# properties next to SetValue I added nice Value setter which changes HasValue as well. Concise, easy to understand and… completely wrong.

I added it to Skila and to my surprise on one end I called SetValue just to observe no value was ever set on the other end. What on the Earth? Well, struct is always passed by value, which means that if Option is returned from property getter or a method, there is a copy returned of real data. I could call SetValue million times and it would not change a thing for stored data (only local, temporary, copy of Option would be changed).

So rule of thumb for C# developer — by default make your structs immutable. For a language/framework designer there is a lesson too — don’t make risky features implicit.

I‘ve recently watched “Essential Truths Everyone Should Know about Performance in a Large Managed Codebase” by Dustin Campbell. It is longer version of an old saying “profiler is your friend” — but what struck me while watching it is that in C# you don’t see bottlenecks. Boxing? Implicit. Unboxing? Implicit. Method wrapping (with boxing)? Implicit.

Add to this a framework which uses object too often, and profiler becomes necessity. And I thought implicit conversion constructors in C++ were bad — boy, you can at least make them explicit by yourself.

Tagged , , , , , ,

Type system — a job for Sisyphus

Motivated by Nimrod I changed my C#-like model to C++-like one (the desire of fast execution also played role, watch fascinating lecture “Modern C++: What You Need to Know” by Herb Sutter). It was crazy move, I know, but at the same time very educational, since I really didn’t designed type system for Skila, but rather borrowed it.

Hard way and depressing (I fixed one thing, just to discover two more flaws) I learned how many issues sound type system involves. Take for example “this” pointer — feature in C#, bug in C++ (yeah, pointer to stack just asks for trouble). A function with interface as parameter — feature in C#, bug in C++ (because of value slicing). And so on and on…

When I came to generic types with constraints my head was already spinning. What worse the syntax enriched with nullable marker is even more cluttered than in C++.

func foo(x ref ~ptr? Vector<Int>)

does not look especially charming, doesn’t it? Explanation: function takes mutable nullable pointer to view (read only) of “Vector” passed by reference.

So honestly I am not sure I will keep this type model, yet some simple tasks in C# are not available exactly because of the type system, like managing the layout of the data in memory, and those simple tasks hurt the performance badly.

I just hope I am not searching for Holy Grail… Except for this, the good news is I’ve done it! Ahead of me is polishing, refactoring and writing more test cases.

Tagged , ,