Eliminating the ability to have Null.

classic Classic list List threaded Threaded
33 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

John A. De Goes

You should stay away from Stax. Stax is designed for experienced developers with a background and interest in high-level, high-productivity functional programming.

Regards,

John A. De Goes
Twitter: @jdegoes
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 9:24 AM, justin_mills wrote:

> Can Stax do flash without nulls, and still let you use haxe normally or do you have to learn a new approach to code, for me stax is a confusion, why use it over normal haxe I am just interested, is it easy to install can I use current haxe code with it or do i mix and match like as3 and haXe can?
>
> --
> haXe - an open source web programming language
> http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Jordo Odroj
In reply to this post by John A. De Goes
John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

John A. De Goes

I am not arguing for null. Stax does not use null internally. If you deal with external interfaces, then you have to deal with null and convert it into an Option. For these cases, the "toOption()" extension method is useful.

Truly, no language should have null. It's a terrible idea. Option/Maybe is a superior way to deal with the problem. A strict nullable type system is probably my second choice.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:

John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Jordo Odroj
Like I said, I like your toOption method and I'll even experiment with it. But it's not a solution, just a way to work with what's already there in a safer maner. I want more help from the compiler, in that you I don't even want a single null to ever accidentally leak into my program. I want to make it impossible to compile the following code:
x = Some(something);
where something is capable of being null.
That means that all data coming from an older api, or a platform, *must* either be expressed as a multitype/option, *xor* fail at runtime when it receives a null back from the api, as it is a system failure - in that you never understood the api you're programming against.

By the way, how did you implement the method call on null? Is it a macro or something?

On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]> wrote:

I am not arguing for null. Stax does not use null internally. If you deal with external interfaces, then you have to deal with null and convert it into an Option. For these cases, the "toOption()" extension method is useful.

Truly, no language should have null. It's a terrible idea. Option/Maybe is a superior way to deal with the problem. A strict nullable type system is probably my second choice.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:

John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

John A. De Goes

I agree with you, but I've talked with Nicolas before about nullability, and he favors weaker restrictions than I do. So I don't think HaXe will ever support either built-in Option/Maybe or nullable type system (I'm happy if I'm wrong).

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:

Like I said, I like your toOption method and I'll even experiment with it. But it's not a solution, just a way to work with what's already there in a safer maner. I want more help from the compiler, in that you I don't even want a single null to ever accidentally leak into my program. I want to make it impossible to compile the following code:
x = Some(something);
where something is capable of being null.
That means that all data coming from an older api, or a platform, *must* either be expressed as a multitype/option, *xor* fail at runtime when it receives a null back from the api, as it is a system failure - in that you never understood the api you're programming against.

By the way, how did you implement the method call on null? Is it a macro or something?

On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]> wrote:

I am not arguing for null. Stax does not use null internally. If you deal with external interfaces, then you have to deal with null and convert it into an Option. For these cases, the "toOption()" extension method is useful.

Truly, no language should have null. It's a terrible idea. Option/Maybe is a superior way to deal with the problem. A strict nullable type system is probably my second choice.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:

John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Jordo Odroj
I hope you're wrong too. :)  But I don't think that he would mind us implementing an optional mode that eliminates (the Null type being a subtype of any object reference), if he would be so kind as to point us in the right direction.
If the objections are that it's harder to work with platforms/preexisting code, I thought that we outlined a few various reasonable migration strategies.


On Fri, Jan 21, 2011 at 6:50 AM, John A. De Goes <[hidden email]> wrote:

I agree with you, but I've talked with Nicolas before about nullability, and he favors weaker restrictions than I do. So I don't think HaXe will ever support either built-in Option/Maybe or nullable type system (I'm happy if I'm wrong).

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:

Like I said, I like your toOption method and I'll even experiment with it. But it's not a solution, just a way to work with what's already there in a safer maner. I want more help from the compiler, in that you I don't even want a single null to ever accidentally leak into my program. I want to make it impossible to compile the following code:
x = Some(something);
where something is capable of being null.
That means that all data coming from an older api, or a platform, *must* either be expressed as a multitype/option, *xor* fail at runtime when it receives a null back from the api, as it is a system failure - in that you never understood the api you're programming against.

By the way, how did you implement the method call on null? Is it a macro or something?

On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]> wrote:

I am not arguing for null. Stax does not use null internally. If you deal with external interfaces, then you have to deal with null and convert it into an Option. For these cases, the "toOption()" extension method is useful.

Truly, no language should have null. It's a terrible idea. Option/Maybe is a superior way to deal with the problem. A strict nullable type system is probably my second choice.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:

John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Tarwin Stroh-Spijer
Hi,

Sorry to keep this going but I'd like to understand exactly WHY nulls are bad. I have some understanding that they can create confusion / errors because a program / function might be written that is expecting an object / value but gets null and this cannot be caught by the compiler as nulls are allowed.

What other problems do you get? How do you specify default parameters if you cannot pass in null into a function? Would you have a default keyword like in switch ?

ie:
function doMyThing(?x:Int = 10, ?y:Int = 10){}
doMyThing(null, 20);

How would the garbage collector work without null values? How would you remove an object reference? You'd need another keyword / type such as "var myObj = none;" would you not?

I understand where multitypes would be good, especially in letting people use, or not use, nulls. What other problems do they introduce though? Does it mean you have to use a switch on any variable that uses a multitype and you end up writing your code surrounded by a whole load of these switch statements?

Thanks for the examples of how you might use this with Option, Short Lambas or Monadic shorthand. The first two, Option and Short Lambas look pretty messy to me / don't make sense to me. I guess I don't quite get what they're doing but just from a code understandability point they look messy. The Monadic example looks nice and neat, though truth to tell I still don't understand the point of Monads even after reading heaps of articles / intros on them. If you could explain what your Monad is doing that'd be helpful.

I think one of the points of haxe is to keep the language as clean as possible. The least amount of unneeded sugar, so you can learn fast, get started fast and build from there. It also makes code readable, and I'm sure it makes making cross platform, well performing code, work well as well.

Regards,


Tarwin Stroh-Spijer
_______________________

Touch My Pixel
http://www.touchmypixel.com/
phone: +61 3 8060 5321
_______________________


On Sat, Jan 22, 2011 at 7:14 AM, Jordo Odroj <[hidden email]> wrote:
I hope you're wrong too. :)  But I don't think that he would mind us implementing an optional mode that eliminates (the Null type being a subtype of any object reference), if he would be so kind as to point us in the right direction.
If the objections are that it's harder to work with platforms/preexisting code, I thought that we outlined a few various reasonable migration strategies.


On Fri, Jan 21, 2011 at 6:50 AM, John A. De Goes <[hidden email]> wrote:

I agree with you, but I've talked with Nicolas before about nullability, and he favors weaker restrictions than I do. So I don't think HaXe will ever support either built-in Option/Maybe or nullable type system (I'm happy if I'm wrong).

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:

Like I said, I like your toOption method and I'll even experiment with it. But it's not a solution, just a way to work with what's already there in a safer maner. I want more help from the compiler, in that you I don't even want a single null to ever accidentally leak into my program. I want to make it impossible to compile the following code:
x = Some(something);
where something is capable of being null.
That means that all data coming from an older api, or a platform, *must* either be expressed as a multitype/option, *xor* fail at runtime when it receives a null back from the api, as it is a system failure - in that you never understood the api you're programming against.

By the way, how did you implement the method call on null? Is it a macro or something?

On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]> wrote:

I am not arguing for null. Stax does not use null internally. If you deal with external interfaces, then you have to deal with null and convert it into an Option. For these cases, the "toOption()" extension method is useful.

Truly, no language should have null. It's a terrible idea. Option/Maybe is a superior way to deal with the problem. A strict nullable type system is probably my second choice.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:

John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Jordo Odroj
Tarwin Stroh-Spijer,

Thanks for the open mind. I'll try to tackle each of your questions:
Defaults: There are several ways to do this that could please everyone, so I won't really go deep here. The only thing to note, is that if your parameter is a multitype of Null | String, then your default value must either be an instance of Null or String.

To be clarify, I am being totally misleading when I say "eliminate null". My main request is to eliminate the fact that Null is always treated as a subtype of any object reference. The result being, if something can be nullable, you need to tell us about it, you don't get it automatically. The benefit, is that the 10% of your code that actually wants to use it, is safer because you always must switch on it - which you should be doing anyways! (or else it's a compiler error) and the other 90% is shorter and cleaner because you can always assume your objects are not null.
In any project, there is some hidden part of the code that assumes that data won't be null but is *wrong* about that assumption. Having to explicitly declare what can be null, completely eliminates these parts of the code, which (as the inventor of null has pointed out - has costed society billions of actual dollars, and possibly lives.)

So yes, you have to switch on these parts of the code, but you *should* be doing something to this effect anyways. Also, to recap:
1. You'll only have to check/switch for nulls in a small part of your codebase, as opposed to the entire thing.
2. The parts that do check will check in such a way that is enforced by your compiler, and will catch bugs at compile time as opposed to deploy time.
3. The other side of the coin, and the best benefit, is that the other 90% of objects that can't be assigned to null, never need to be checked, resulting in a smaller, cleaner, safer code base, just as you desire.
4. So multitypes/switching doesn't make your code base more verbose. In fact it makes it more succinct!

Once you try it, you will be hooked. I suggest going through ML (language) and try programming with it for a weekend. You'll be amazed at how helpful the type system can be at compilation time.

Garbage Collection: No worries here. This is mostly compilation time assistance that reduces to almost the same exact code as if you were to assign nulls to object references. The only differences is that we'd like the compiler to help us out to make sure we're doing it right, so we can have a smaller, safer code base.

On Sun, Jan 23, 2011 at 10:54 PM, Tarwin Stroh-Spijer <[hidden email]> wrote:
Hi,

Sorry to keep this going but I'd like to understand exactly WHY nulls are bad. I have some understanding that they can create confusion / errors because a program / function might be written that is expecting an object / value but gets null and this cannot be caught by the compiler as nulls are allowed.

What other problems do you get? How do you specify default parameters if you cannot pass in null into a function? Would you have a default keyword like in switch ?

ie:
function doMyThing(?x:Int = 10, ?y:Int = 10){}
doMyThing(null, 20);

How would the garbage collector work without null values? How would you remove an object reference? You'd need another keyword / type such as "var myObj = none;" would you not?

I understand where multitypes would be good, especially in letting people use, or not use, nulls. What other problems do they introduce though? Does it mean you have to use a switch on any variable that uses a multitype and you end up writing your code surrounded by a whole load of these switch statements?

Thanks for the examples of how you might use this with Option, Short Lambas or Monadic shorthand. The first two, Option and Short Lambas look pretty messy to me / don't make sense to me. I guess I don't quite get what they're doing but just from a code understandability point they look messy. The Monadic example looks nice and neat, though truth to tell I still don't understand the point of Monads even after reading heaps of articles / intros on them. If you could explain what your Monad is doing that'd be helpful.

I think one of the points of haxe is to keep the language as clean as possible. The least amount of unneeded sugar, so you can learn fast, get started fast and build from there. It also makes code readable, and I'm sure it makes making cross platform, well performing code, work well as well.

Regards,


Tarwin Stroh-Spijer
_______________________

Touch My Pixel
http://www.touchmypixel.com/
phone: +61 3 8060 5321
_______________________


On Sat, Jan 22, 2011 at 7:14 AM, Jordo Odroj <[hidden email]> wrote:
I hope you're wrong too. :)  But I don't think that he would mind us implementing an optional mode that eliminates (the Null type being a subtype of any object reference), if he would be so kind as to point us in the right direction.
If the objections are that it's harder to work with platforms/preexisting code, I thought that we outlined a few various reasonable migration strategies.


On Fri, Jan 21, 2011 at 6:50 AM, John A. De Goes <[hidden email]> wrote:

I agree with you, but I've talked with Nicolas before about nullability, and he favors weaker restrictions than I do. So I don't think HaXe will ever support either built-in Option/Maybe or nullable type system (I'm happy if I'm wrong).

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:

Like I said, I like your toOption method and I'll even experiment with it. But it's not a solution, just a way to work with what's already there in a safer maner. I want more help from the compiler, in that you I don't even want a single null to ever accidentally leak into my program. I want to make it impossible to compile the following code:
x = Some(something);
where something is capable of being null.
That means that all data coming from an older api, or a platform, *must* either be expressed as a multitype/option, *xor* fail at runtime when it receives a null back from the api, as it is a system failure - in that you never understood the api you're programming against.

By the way, how did you implement the method call on null? Is it a macro or something?

On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]> wrote:

I am not arguing for null. Stax does not use null internally. If you deal with external interfaces, then you have to deal with null and convert it into an Option. For these cases, the "toOption()" extension method is useful.

Truly, no language should have null. It's a terrible idea. Option/Maybe is a superior way to deal with the problem. A strict nullable type system is probably my second choice.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:

John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Tarwin Stroh-Spijer
I'm still a little confused about the garbage collection stuff. If you want to be able to tell something to be able to be garbage collected at some time, you're going to have to always have it multityped as Null | SomethingElse right? Otherwise you'll never going to be able to compile:

var myX:SomethingElse = new SomethingElse(); // create
myX = null; // allow garbage collection

Regards,


Tarwin Stroh-Spijer
_______________________

Touch My Pixel
http://www.touchmypixel.com/
phone: +61 3 8060 5321
_______________________


On Mon, Jan 24, 2011 at 7:04 PM, Jordo Odroj <[hidden email]> wrote:
Tarwin Stroh-Spijer,

Thanks for the open mind. I'll try to tackle each of your questions:
Defaults: There are several ways to do this that could please everyone, so I won't really go deep here. The only thing to note, is that if your parameter is a multitype of Null | String, then your default value must either be an instance of Null or String.

To be clarify, I am being totally misleading when I say "eliminate null". My main request is to eliminate the fact that Null is always treated as a subtype of any object reference. The result being, if something can be nullable, you need to tell us about it, you don't get it automatically. The benefit, is that the 10% of your code that actually wants to use it, is safer because you always must switch on it - which you should be doing anyways! (or else it's a compiler error) and the other 90% is shorter and cleaner because you can always assume your objects are not null.
In any project, there is some hidden part of the code that assumes that data won't be null but is *wrong* about that assumption. Having to explicitly declare what can be null, completely eliminates these parts of the code, which (as the inventor of null has pointed out - has costed society billions of actual dollars, and possibly lives.)

So yes, you have to switch on these parts of the code, but you *should* be doing something to this effect anyways. Also, to recap:
1. You'll only have to check/switch for nulls in a small part of your codebase, as opposed to the entire thing.
2. The parts that do check will check in such a way that is enforced by your compiler, and will catch bugs at compile time as opposed to deploy time.
3. The other side of the coin, and the best benefit, is that the other 90% of objects that can't be assigned to null, never need to be checked, resulting in a smaller, cleaner, safer code base, just as you desire.
4. So multitypes/switching doesn't make your code base more verbose. In fact it makes it more succinct!

Once you try it, you will be hooked. I suggest going through ML (language) and try programming with it for a weekend. You'll be amazed at how helpful the type system can be at compilation time.

Garbage Collection: No worries here. This is mostly compilation time assistance that reduces to almost the same exact code as if you were to assign nulls to object references. The only differences is that we'd like the compiler to help us out to make sure we're doing it right, so we can have a smaller, safer code base.

On Sun, Jan 23, 2011 at 10:54 PM, Tarwin Stroh-Spijer <[hidden email]> wrote:
Hi,

Sorry to keep this going but I'd like to understand exactly WHY nulls are bad. I have some understanding that they can create confusion / errors because a program / function might be written that is expecting an object / value but gets null and this cannot be caught by the compiler as nulls are allowed.

What other problems do you get? How do you specify default parameters if you cannot pass in null into a function? Would you have a default keyword like in switch ?

ie:
function doMyThing(?x:Int = 10, ?y:Int = 10){}
doMyThing(null, 20);

How would the garbage collector work without null values? How would you remove an object reference? You'd need another keyword / type such as "var myObj = none;" would you not?

I understand where multitypes would be good, especially in letting people use, or not use, nulls. What other problems do they introduce though? Does it mean you have to use a switch on any variable that uses a multitype and you end up writing your code surrounded by a whole load of these switch statements?

Thanks for the examples of how you might use this with Option, Short Lambas or Monadic shorthand. The first two, Option and Short Lambas look pretty messy to me / don't make sense to me. I guess I don't quite get what they're doing but just from a code understandability point they look messy. The Monadic example looks nice and neat, though truth to tell I still don't understand the point of Monads even after reading heaps of articles / intros on them. If you could explain what your Monad is doing that'd be helpful.

I think one of the points of haxe is to keep the language as clean as possible. The least amount of unneeded sugar, so you can learn fast, get started fast and build from there. It also makes code readable, and I'm sure it makes making cross platform, well performing code, work well as well.

Regards,


Tarwin Stroh-Spijer
_______________________

Touch My Pixel
http://www.touchmypixel.com/
phone: +61 3 8060 5321
_______________________


On Sat, Jan 22, 2011 at 7:14 AM, Jordo Odroj <[hidden email]> wrote:
I hope you're wrong too. :)  But I don't think that he would mind us implementing an optional mode that eliminates (the Null type being a subtype of any object reference), if he would be so kind as to point us in the right direction.
If the objections are that it's harder to work with platforms/preexisting code, I thought that we outlined a few various reasonable migration strategies.


On Fri, Jan 21, 2011 at 6:50 AM, John A. De Goes <[hidden email]> wrote:

I agree with you, but I've talked with Nicolas before about nullability, and he favors weaker restrictions than I do. So I don't think HaXe will ever support either built-in Option/Maybe or nullable type system (I'm happy if I'm wrong).

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:

Like I said, I like your toOption method and I'll even experiment with it. But it's not a solution, just a way to work with what's already there in a safer maner. I want more help from the compiler, in that you I don't even want a single null to ever accidentally leak into my program. I want to make it impossible to compile the following code:
x = Some(something);
where something is capable of being null.
That means that all data coming from an older api, or a platform, *must* either be expressed as a multitype/option, *xor* fail at runtime when it receives a null back from the api, as it is a system failure - in that you never understood the api you're programming against.

By the way, how did you implement the method call on null? Is it a macro or something?

On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]> wrote:

I am not arguing for null. Stax does not use null internally. If you deal with external interfaces, then you have to deal with null and convert it into an Option. For these cases, the "toOption()" extension method is useful.

Truly, no language should have null. It's a terrible idea. Option/Maybe is a superior way to deal with the problem. A strict nullable type system is probably my second choice.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:

John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Jordo Odroj
Correct me if I'm wrong, but there are only a few cases where you need to explicitly tell the garbage collector to free an object in a managed environment. One example, is if you're managing a data structure such as a queue. The queue is typically implemented with a fixed pool of memory, of which we use as much as we need and grow the pool if we need to. The easiest way to "pop" off of the queue is to null out the last element and keep track of where the new last element is. These types of cases are quite rare. Usually, (not as in our queue case), no references to an object - and needing to be garbage collected are equivalent.
But in this case:
1. I would have the data structure implementation have a fixed pool of Null | ElementType. Or you can typedef NullableElement = Null | ElementType.
2. When you need to indicate that something should be garbage collected, set the cell to null (which is of type Null). Just the same as you're used to, and it's actually no extra work because you've told the system that the buffer holds Null | ElementType.
3. Now here's where the real meaty question happens. What is the interface to your queue? Is it Queue<ElementType> or Queue<Null | ElementType>?
In the later case, the solution is easy. There is no additional work.  Just return what is in the cell that you dequeue from. In the first case,
if someone dequeues something, and the contents of what you're about to dequeue is Null (instead of type ElementType) that is an indication that you have a programming error. This is a great use case for why multitypes are better even in these strange edge cases. The interface looks like:
public function dequeue() : ElementType {...}
This needs to return an ElementType or fail. Null should never be returned because (in our happy little world) Null is not a subtype of ElementType.
Now in your queue code, you HAVE to check if the result is null before returning something to the client, because the compiler makes you! While you're checking for null, and you find it, you may as well throw an exception as it indicates programmer error.

Enqueueing is easy, because the user is inserting ElementType elements, and that happens to be a subtype of Null | ElementType.

In summary, the gc situations rarely come up, but that's great that you thought of that, however, there's always a solution with multitypes that actually produce cleaner, shorter, and simpler code.

On Mon, Jan 24, 2011 at 12:31 AM, Tarwin Stroh-Spijer <[hidden email]> wrote:
I'm still a little confused about the garbage collection stuff. If you want to be able to tell something to be able to be garbage collected at some time, you're going to have to always have it multityped as Null | SomethingElse right? Otherwise you'll never going to be able to compile:

var myX:SomethingElse = new SomethingElse(); // create
myX = null; // allow garbage collection

Regards,


Tarwin Stroh-Spijer
_______________________

Touch My Pixel
http://www.touchmypixel.com/
phone: +61 3 8060 5321
_______________________


On Mon, Jan 24, 2011 at 7:04 PM, Jordo Odroj <[hidden email]> wrote:
Tarwin Stroh-Spijer,

Thanks for the open mind. I'll try to tackle each of your questions:
Defaults: There are several ways to do this that could please everyone, so I won't really go deep here. The only thing to note, is that if your parameter is a multitype of Null | String, then your default value must either be an instance of Null or String.

To be clarify, I am being totally misleading when I say "eliminate null". My main request is to eliminate the fact that Null is always treated as a subtype of any object reference. The result being, if something can be nullable, you need to tell us about it, you don't get it automatically. The benefit, is that the 10% of your code that actually wants to use it, is safer because you always must switch on it - which you should be doing anyways! (or else it's a compiler error) and the other 90% is shorter and cleaner because you can always assume your objects are not null.
In any project, there is some hidden part of the code that assumes that data won't be null but is *wrong* about that assumption. Having to explicitly declare what can be null, completely eliminates these parts of the code, which (as the inventor of null has pointed out - has costed society billions of actual dollars, and possibly lives.)

So yes, you have to switch on these parts of the code, but you *should* be doing something to this effect anyways. Also, to recap:
1. You'll only have to check/switch for nulls in a small part of your codebase, as opposed to the entire thing.
2. The parts that do check will check in such a way that is enforced by your compiler, and will catch bugs at compile time as opposed to deploy time.
3. The other side of the coin, and the best benefit, is that the other 90% of objects that can't be assigned to null, never need to be checked, resulting in a smaller, cleaner, safer code base, just as you desire.
4. So multitypes/switching doesn't make your code base more verbose. In fact it makes it more succinct!

Once you try it, you will be hooked. I suggest going through ML (language) and try programming with it for a weekend. You'll be amazed at how helpful the type system can be at compilation time.

Garbage Collection: No worries here. This is mostly compilation time assistance that reduces to almost the same exact code as if you were to assign nulls to object references. The only differences is that we'd like the compiler to help us out to make sure we're doing it right, so we can have a smaller, safer code base.

On Sun, Jan 23, 2011 at 10:54 PM, Tarwin Stroh-Spijer <[hidden email]> wrote:
Hi,

Sorry to keep this going but I'd like to understand exactly WHY nulls are bad. I have some understanding that they can create confusion / errors because a program / function might be written that is expecting an object / value but gets null and this cannot be caught by the compiler as nulls are allowed.

What other problems do you get? How do you specify default parameters if you cannot pass in null into a function? Would you have a default keyword like in switch ?

ie:
function doMyThing(?x:Int = 10, ?y:Int = 10){}
doMyThing(null, 20);

How would the garbage collector work without null values? How would you remove an object reference? You'd need another keyword / type such as "var myObj = none;" would you not?

I understand where multitypes would be good, especially in letting people use, or not use, nulls. What other problems do they introduce though? Does it mean you have to use a switch on any variable that uses a multitype and you end up writing your code surrounded by a whole load of these switch statements?

Thanks for the examples of how you might use this with Option, Short Lambas or Monadic shorthand. The first two, Option and Short Lambas look pretty messy to me / don't make sense to me. I guess I don't quite get what they're doing but just from a code understandability point they look messy. The Monadic example looks nice and neat, though truth to tell I still don't understand the point of Monads even after reading heaps of articles / intros on them. If you could explain what your Monad is doing that'd be helpful.

I think one of the points of haxe is to keep the language as clean as possible. The least amount of unneeded sugar, so you can learn fast, get started fast and build from there. It also makes code readable, and I'm sure it makes making cross platform, well performing code, work well as well.

Regards,


Tarwin Stroh-Spijer
_______________________

Touch My Pixel
http://www.touchmypixel.com/
phone: +61 3 8060 5321
_______________________


On Sat, Jan 22, 2011 at 7:14 AM, Jordo Odroj <[hidden email]> wrote:
I hope you're wrong too. :)  But I don't think that he would mind us implementing an optional mode that eliminates (the Null type being a subtype of any object reference), if he would be so kind as to point us in the right direction.
If the objections are that it's harder to work with platforms/preexisting code, I thought that we outlined a few various reasonable migration strategies.


On Fri, Jan 21, 2011 at 6:50 AM, John A. De Goes <[hidden email]> wrote:

I agree with you, but I've talked with Nicolas before about nullability, and he favors weaker restrictions than I do. So I don't think HaXe will ever support either built-in Option/Maybe or nullable type system (I'm happy if I'm wrong).

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:

Like I said, I like your toOption method and I'll even experiment with it. But it's not a solution, just a way to work with what's already there in a safer maner. I want more help from the compiler, in that you I don't even want a single null to ever accidentally leak into my program. I want to make it impossible to compile the following code:
x = Some(something);
where something is capable of being null.
That means that all data coming from an older api, or a platform, *must* either be expressed as a multitype/option, *xor* fail at runtime when it receives a null back from the api, as it is a system failure - in that you never understood the api you're programming against.

By the way, how did you implement the method call on null? Is it a macro or something?

On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]> wrote:

I am not arguing for null. Stax does not use null internally. If you deal with external interfaces, then you have to deal with null and convert it into an Option. For these cases, the "toOption()" extension method is useful.

Truly, no language should have null. It's a terrible idea. Option/Maybe is a superior way to deal with the problem. A strict nullable type system is probably my second choice.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:

John, I like it but it doesn't solve the problem.
If you look at all of your code, all of the places that have object references. The places that actually take advantage of null being a subtype of object reference, is probably about 10% or less. With the other 90+%, we need the ability to reason about objects, with certainty that objects are not null. That means that you don't ever have to check if they're null, because the compiler would have caught this.
So the result is, 90% of your code is more compact because you never have to check for nulls, and more safe because runtime exceptions will be thrown in fewer unanticipated locations (which sometimes prevent system/network/db resources from being cleaned up properly). For the other ten percent, the compiler *forces* you to check both options (null vs. not null).
As Heinz says, even with great "Options" enums (which are a step in the right direction) you can't prevent Some(null) at compile time. Also, right now, *every* object reference possibly contains a null value. So if you really want safe code you need to always transform every object using possiblyNullValue.toOption(). The goal is that for the 90+% of the code where we don't utilize null, we don't need to do additional work, but rather for the 10% of the code that does, we'll tolerate a little more work.

On the note of checking deep structures with nullability, we have the luxury of creating great compile time constructs such as:
Given:
enum Option...
And assuming that Strings can never be null (remember we're in happy no-null land)
typedef Foo = {
   var possibleBar : Option<Bar>;   // Foo contains an optional bar
   var alwaysString : String; // Shan't be null due to our awesomeness
}
Haxe could employ deep pattern matching on Option<Foo> like this:
var optionalFoo : Option<Foo> = ...
var result = match(optionalFoo) {              // much like switch but deep
     some(foo(some(bar), str)) :
         "foo had nonempty bar" + str;
     some(foo(none, str)): 
          "Foo had an empty bar" + str;
     none: 
          "didn't even have a foo !";
}
I maybe didn't get the syntax right, but something like that could be quite easy to manage. If you don't like it, please suggest something that is more compact, and equally expressive.
Notice how, we KNOW that the string concatenation could never fail (assuming concat of null string fails - which it SHOULD IMHO). The important thing is that I never had to check on the nullness of the string because I know the compiler enforced it already.

The same thing could easily be applied to multitypes.
The multitypes (as proposed) seem to just be sugar for automatically creating an enum. I like haxe enums (except for the ability to null out things in an Option<> enum (which we'll hopefully get rid of by my proposition)), and I like the proposal for multitypes because they make enums more convenient.

Nicolas, if you're still tuning into this, how can I get started?
I'd like to implement the following:
1. A deep (comprehensive -fails when I don't cover all cases) pattern matching system.
2. Eliminating the null keyword, and making the bridge between haxe code that has nulls, as well as platform calls (using multitypes?)
3. (Secret third option: Awesome multitypes) See below:
->ML lets you name what we are calling multitypes, You can say typedef Automobile = Car | Motocycle; (that would be cool because then you could have other multitypes inside of multitypes:
typedef TransportMethod = Automobile | Run | Bike (where automobile is already a multitype.
-> Deep multitype definitions. The previous could be expressed as:
 typedef TransportMethod = (Car | MotorCycle) | Run | Bike
Look how powerful that single line is. 
-> Deep pattern matching, as explained before. There's a great pattern matching macro, but I do not believe it does comprehensive checks, and redundancy checks like ML tries hard to do. 



On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]> wrote:

True, although if you're using Stax, you should use toOption(), e.g.:

null.toOption();

Or:

possiblyNullValue.toOption();

This will ensure you don't ever have to deal with nulls.

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:

Yes, nullability is a big problem.

Let's take this code for example:

enum Option<T> {
    Some(a:T);
    None;
}

var opt = Some(null); // legal code and passing null to an enum constructor can't even be checked inside of the constructor.

Am 20.01.2011 07:53, schrieb Jordo Odroj:
There are many ways to go about this. After thinking about it for a while, it makes sense to employ the convention that any result from another platform must be multityped with Null. This seems pretty simple to make a compiler option for. (I trivialize the matter, but here is the high level description of how we can go about integrating with platforms)
Also, any library that was written under the assumption that Null *SHOULD* be a subtype of any other object reference, we could do the same thing for.

The haxe compiler would have something like:
if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I propose
     // null is not a valid keyword anywhere,
     // all objects coming from other platforms must be multityped with Null
     // for all libraries that are not written in this special mode, enforce that their return values must be received as multityped with Null
} else {
    // procede as current
}

The two challenges are integrating with platforms, and preexisting libraries. Both of which seem pretty straightforward to at least *describe* at a high level. The implementation could be very difficult. I only have a bit of ML experience, but I can take a stab at this if someone would implement multitypes, and point me in the right direction. In my opinion, haxe is at it's infant stages. I want this language to succeed, because I acknowledge that it hits all the right marks for the current state of web and mobile technology. 
(Note, I'm not assuming that multitypes are the absolute best solution, I'm willing to hear what other's favorites are but the general concept should be the same as far as integrating this with other code):


If you need further convincing, you can consider the opinion of the original "inventor" of null:

" I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
C.A.R. Hoare

We have the *luxury* of being in the beginning stages of haxe. Note that by "beginning stages" I don't mean that haxe is underdeveloped, but that I see huge possibilities for it. Eliminating null is going to be a great step in this direction.

Jordo

On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]> wrote:
My not employ ML style pattern matching that allows you to express structural depth quite easilly? I recalled using them years ago and they were quite powerful.

On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]> wrote:

That's not a good solution. Scala allows arbitrary switching on value types. So, for example, you can write:

val x = y match { case foo: Foo => 1 }

This is more difficult in HaXe because the "has type" operator ":" is overloaded with another meaning inside case expressions. Still, it should be possible to parse something like:

var x = switch(y) {
  case foo: Foo: 1
}

This code would work with any "y", even if not a multitype. Then, when multitypes are added, no special feature or unique syntax needs to be introduced in order to deal with them:

var y: Int | String = "foo";

var x = switch(y) {
  case anyInt: Int: Std.string(anyInt);
  case anyString: String: anyString;
}

Regards,

John A. De Goes
Twitter: @jdegoes 
LinkedIn: http://linkedin.com/in/jdegoes

On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:

Hi, I find this mutliType feature amazing, and I agree with Jordo on the null thing,
I'm just willing to ask about the syntax you're employing, I've seen foo( x : A|B ) and foo( T : A|B )
what is the reflexion beyond that syntax ?
I'm a little afraid of having to do unclear things to handle that feature such as the given example
function foo( x : A|B) {
    switch( x ) {
        case A : //
        case B : //
    }
}
It doesn't seems clear that we are talking about type in this switch-case, and what if I would like to actually switch on that value ?
Could it be a more like defining a pseudo Type, like
function foo( x : T(Int|String) ) {
    switch ( T ) {
        case Int :  
                        switch ( x ) {
                                case 1 : //
                                case 2 : //
                        }
        case String :
                        foo( Std.parseInt( x ) ) ;
}
that's just some thoughts,
 
Renaud

Sent: Monday, January 17, 2011 12:22 PM
Subject: Re: [haXe] Eliminating the ability to have Null.

Oh, and I've never got the chance to thank you, Nicolas, for your awesome and, quite frankly, elegant invention Haxe. I really don't even know how to show my thanks. It's been nothing but a joy to be working with Haxe.
The request to eliminate null, is merely an attempt to take care of the one remaining language feature that I consider to be "impure".
With "untyped" and Dynamic, you (the programmer) declare that you wish to break type safety, and otherwise the experience is very pure. However, null is this evil concept that breaks the type system "on your behalf" without ever asking you, and without you ever indicating that it should. It's the only inconsistency that I've found in the language so far.
Thanks again.

On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]> wrote:
Nicolas, the longer we wait, the harder it will be. If we had multitypes, it wouldn't even have to be Null<ClassName> It would just be:
var x = function (x: MyClass | Null) {

}

If you know that a platform api could return null, then you define the haxe bindings *at the bridge point into the other platform* such that all things that could return null, return Null | TheOtherType. Then, you keep all things pure in haxe land. If anything returns null from another platform api (php etc) when the bindings did *not* indicate Null | Othertype, then that is a runtime system failure. Then we can switch on a compiler mode, where any reference to null is a compiler error (in haxe code). Any api into another platform that comes back null, without defining the return type from the platform api to be Null | OtherType would be a runtime failure. Because, let's face it, you should know the api's well enough to be able to indicate whether or not they return null anyways, so it's not unreasonable to require that a developer indicate this in the platform api's return type. In fact, once we document it, we'll save them much trouble later on.
I think we could do this. Nicolas, I only have a little ML experience, but do you think it would be reasonable for me to implement this? 
As someone who write OCaml, Nicolas, I was hoping you would appreciate where I am coming from. The stronger the typing the less errors we experience in production, and this saves us all time, money, and stress.

This is one of those things, where if you never knew you could have it, you'd never long for it, but once you try it, you'll never want to go back.

Jordo

On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse <[hidden email]> wrote:
Le 17/01/2011 08:14, Jordo Odroj a écrit :

Hello,

I've always found that having the option to set an object's value to
null is the worst feature of virtually every single language
in existence. Why can't we have the haxe language support None |
Some<Type> instead?

The issue is not the language itself, since it's not that much hard to enforce not-nullness of class members - it still requires some extensive analysis of class constructor call.

The main issue is that many platform API have not been designed with such feature in mind, and that would require the developer to either propagates Null<Foo> types or add == null checks in many places.

I might at some point in the future make some experiments with this, but it's not high priority.

Nicolas

--
haXe - an open source web programming language
http://haxe.org





--
haXe - an open source web programming language
http://haxe.org
--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org

--
haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--

haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Robin Palotai
I did not confirm myself, but read that the Flash gc can be really bad-behaved:
1) It doesn't necessarily resolve cyclic dependencies (maybe the
language standard doesn't require it explicitly, but writing out of
memory here)
2) More suprisingly, some found that it may not release non-cyclic
islands which are "big enough".

Therefore hand-nulling things in the Flash environment could be an
active practice.

Robin

On Mon, Jan 24, 2011 at 10:21 AM, Jordo Odroj <[hidden email]> wrote:

> Correct me if I'm wrong, but there are only a few cases where you need
> to explicitly tell the garbage collector to free an object in a managed
> environment. One example, is if you're managing a data structure such as a
> queue. The queue is typically implemented with a fixed pool of memory, of
> which we use as much as we need and grow the pool if we need to. The easiest
> way to "pop" off of the queue is to null out the last element and keep track
> of where the new last element is. These types of cases are quite rare.
> Usually, (not as in our queue case), no references to an object - and
> needing to be garbage collected are equivalent.
> But in this case:
> 1. I would have the data structure implementation have a fixed pool of Null
> | ElementType. Or you can typedef NullableElement = Null | ElementType.
> 2. When you need to indicate that something should be garbage collected, set
> the cell to null (which is of type Null). Just the same as you're used to,
> and it's actually no extra work because you've told the system that the
> buffer holds Null | ElementType.
> 3. Now here's where the real meaty question happens. What is the interface
> to your queue? Is it Queue<ElementType> or Queue<Null | ElementType>?
> In the later case, the solution is easy. There is no additional work.  Just
> return what is in the cell that you dequeue from. In the first case,
> if someone dequeues something, and the contents of what you're about to
> dequeue is Null (instead of type ElementType) that is an indication that you
> have a programming error. This is a great use case for why multitypes are
> better even in these strange edge cases. The interface looks like:
> public function dequeue() : ElementType {...}
> This needs to return an ElementType or fail. Null should never be returned
> because (in our happy little world) Null is not a subtype of ElementType.
> Now in your queue code, you HAVE to check if the result is null before
> returning something to the client, because the compiler makes you! While
> you're checking for null, and you find it, you may as well throw an
> exception as it indicates programmer error.
> Enqueueing is easy, because the user is inserting ElementType elements, and
> that happens to be a subtype of Null | ElementType.
> In summary, the gc situations rarely come up, but that's great that you
> thought of that, however, there's always a solution with multitypes that
> actually produce cleaner, shorter, and simpler code.
> On Mon, Jan 24, 2011 at 12:31 AM, Tarwin Stroh-Spijer
> <[hidden email]> wrote:
>>
>> I'm still a little confused about the garbage collection stuff. If you
>> want to be able to tell something to be able to be garbage collected at some
>> time, you're going to have to always have it multityped as Null |
>> SomethingElse right? Otherwise you'll never going to be able to compile:
>> var myX:SomethingElse = new SomethingElse(); // create
>> myX = null; // allow garbage collection
>> Regards,
>>
>>
>> Tarwin Stroh-Spijer
>> _______________________
>>
>> Touch My Pixel
>> http://www.touchmypixel.com/
>> phone: +61 3 8060 5321
>> _______________________
>>
>>
>> On Mon, Jan 24, 2011 at 7:04 PM, Jordo Odroj <[hidden email]> wrote:
>>>
>>> Tarwin Stroh-Spijer,
>>> Thanks for the open mind. I'll try to tackle each of your questions:
>>> Defaults: There are several ways to do this that could please everyone,
>>> so I won't really go deep here. The only thing to note, is that if your
>>> parameter is a multitype of Null | String, then your default value must
>>> either be an instance of Null or String.
>>> To be clarify, I am being totally misleading when I say "eliminate null".
>>> My main request is to eliminate the fact that Null is always treated as a
>>> subtype of any object reference. The result being, if something can be
>>> nullable, you need to tell us about it, you don't get it automatically. The
>>> benefit, is that the 10% of your code that actually wants to use it, is
>>> safer because you always must switch on it - which you should be doing
>>> anyways! (or else it's a compiler error) and the other 90% is shorter and
>>> cleaner because you can always assume your objects are not null.
>>> In any project, there is some hidden part of the code that assumes that
>>> data won't be null but is *wrong* about that assumption. Having to
>>> explicitly declare what can be null, completely eliminates these parts of
>>> the code, which (as the inventor of null has pointed out - has costed
>>> society billions of actual dollars, and possibly lives.)
>>> So yes, you have to switch on these parts of the code, but you *should*
>>> be doing something to this effect anyways. Also, to recap:
>>> 1. You'll only have to check/switch for nulls in a small part of your
>>> codebase, as opposed to the entire thing.
>>> 2. The parts that do check will check in such a way that is enforced by
>>> your compiler, and will catch bugs at compile time as opposed to deploy
>>> time.
>>> 3. The other side of the coin, and the best benefit, is that the other
>>> 90% of objects that can't be assigned to null, never need to be checked,
>>> resulting in a smaller, cleaner, safer code base, just as you desire.
>>> 4. So multitypes/switching doesn't make your code base more verbose. In
>>> fact it makes it more succinct!
>>> Once you try it, you will be hooked. I suggest going through ML
>>> (language) and try programming with it for a weekend. You'll be amazed at
>>> how helpful the type system can be at compilation time.
>>> Garbage Collection: No worries here. This is mostly compilation time
>>> assistance that reduces to almost the same exact code as if you were to
>>> assign nulls to object references. The only differences is that we'd like
>>> the compiler to help us out to make sure we're doing it right, so we can
>>> have a smaller, safer code base.
>>> On Sun, Jan 23, 2011 at 10:54 PM, Tarwin Stroh-Spijer
>>> <[hidden email]> wrote:
>>>>
>>>> Hi,
>>>> Sorry to keep this going but I'd like to understand exactly WHY nulls
>>>> are bad. I have some understanding that they can create confusion / errors
>>>> because a program / function might be written that is expecting an object /
>>>> value but gets null and this cannot be caught by the compiler as nulls are
>>>> allowed.
>>>> What other problems do you get? How do you specify default parameters if
>>>> you cannot pass in null into a function? Would you have a default keyword
>>>> like in switch ?
>>>> ie:
>>>> function doMyThing(?x:Int = 10, ?y:Int = 10){}
>>>> doMyThing(null, 20);
>>>>
>>>> How would the garbage collector work without null values? How would you
>>>> remove an object reference? You'd need another keyword / type such as "var
>>>> myObj = none;" would you not?
>>>> I understand where multitypes would be good, especially in letting
>>>> people use, or not use, nulls. What other problems do they introduce though?
>>>> Does it mean you have to use a switch on any variable that uses a multitype
>>>> and you end up writing your code surrounded by a whole load of these switch
>>>> statements?
>>>> Thanks for the examples of how you might use this with Option, Short
>>>> Lambas or Monadic shorthand. The first two, Option and Short Lambas look
>>>> pretty messy to me / don't make sense to me. I guess I don't quite get what
>>>> they're doing but just from a code understandability point they look messy.
>>>> The Monadic example looks nice and neat, though truth to tell I still don't
>>>> understand the point of Monads even after reading heaps of articles / intros
>>>> on them. If you could explain what your Monad is doing that'd be helpful.
>>>> I think one of the points of haxe is to keep the language as clean as
>>>> possible. The least amount of unneeded sugar, so you can learn fast, get
>>>> started fast and build from there. It also makes code readable, and I'm sure
>>>> it makes making cross platform, well performing code, work well as well.
>>>> Regards,
>>>>
>>>> Tarwin Stroh-Spijer
>>>> _______________________
>>>>
>>>> Touch My Pixel
>>>> http://www.touchmypixel.com/
>>>> phone: +61 3 8060 5321
>>>> _______________________
>>>>
>>>>
>>>> On Sat, Jan 22, 2011 at 7:14 AM, Jordo Odroj <[hidden email]> wrote:
>>>>>
>>>>> I hope you're wrong too. :)  But I don't think that he would mind us
>>>>> implementing an optional mode that eliminates (the Null type being a subtype
>>>>> of any object reference), if he would be so kind as to point us in the right
>>>>> direction.
>>>>> If the objections are that it's harder to work with
>>>>> platforms/preexisting code, I thought that we outlined a few various
>>>>> reasonable migration strategies.
>>>>>
>>>>> On Fri, Jan 21, 2011 at 6:50 AM, John A. De Goes <[hidden email]>
>>>>> wrote:
>>>>>>
>>>>>> I agree with you, but I've talked with Nicolas before about
>>>>>> nullability, and he favors weaker restrictions than I do. So I don't think
>>>>>> HaXe will ever support either built-in Option/Maybe or nullable type system
>>>>>> (I'm happy if I'm wrong).
>>>>>> Regards,
>>>>>> John A. De Goes
>>>>>> Twitter: @jdegoes
>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>> On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:
>>>>>>
>>>>>> Like I said, I like your toOption method and I'll even experiment with
>>>>>> it. But it's not a solution, just a way to work with what's already there in
>>>>>> a safer maner. I want more help from the compiler, in that you I don't even
>>>>>> want a single null to ever accidentally leak into my program. I want to make
>>>>>> it impossible to compile the following code:
>>>>>> x = Some(something);
>>>>>> where something is capable of being null.
>>>>>> That means that all data coming from an older api, or a platform,
>>>>>> *must* either be expressed as a multitype/option, *xor* fail at runtime when
>>>>>> it receives a null back from the api, as it is a system failure - in that
>>>>>> you never understood the api you're programming against.
>>>>>>
>>>>>> By the way, how did you implement the method call on null? Is it a
>>>>>> macro or something?
>>>>>>
>>>>>> On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]>
>>>>>> wrote:
>>>>>>>
>>>>>>> I am not arguing for null. Stax does not use null internally. If you
>>>>>>> deal with external interfaces, then you have to deal with null and convert
>>>>>>> it into an Option. For these cases, the "toOption()" extension method is
>>>>>>> useful.
>>>>>>> Truly, no language should have null. It's a terrible idea.
>>>>>>> Option/Maybe is a superior way to deal with the problem. A strict nullable
>>>>>>> type system is probably my second choice.
>>>>>>> Regards,
>>>>>>> John A. De Goes
>>>>>>> Twitter: @jdegoes
>>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>>> On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:
>>>>>>>
>>>>>>> John, I like it but it doesn't solve the problem.
>>>>>>> If you look at all of your code, all of the places that have object
>>>>>>> references. The places that actually take advantage of null being a subtype
>>>>>>> of object reference, is probably about 10% or less. With the other 90+%, we
>>>>>>> need the ability to reason about objects, with certainty that objects are
>>>>>>> not null. That means that you don't ever have to check if they're null,
>>>>>>> because the compiler would have caught this.
>>>>>>> So the result is, 90% of your code is more compact because you never
>>>>>>> have to check for nulls, and more safe because runtime exceptions will be
>>>>>>> thrown in fewer unanticipated locations (which sometimes prevent
>>>>>>> system/network/db resources from being cleaned up properly). For the other
>>>>>>> ten percent, the compiler *forces* you to check both options (null vs. not
>>>>>>> null).
>>>>>>> As Heinz says, even with great "Options" enums (which are a step in
>>>>>>> the right direction) you can't prevent Some(null) at compile time. Also,
>>>>>>> right now, *every* object reference possibly contains a null value. So if
>>>>>>> you really want safe code you need to always transform every object using
>>>>>>> possiblyNullValue.toOption(). The goal is that for the 90+% of the code
>>>>>>> where we don't utilize null, we don't need to do additional work, but rather
>>>>>>> for the 10% of the code that does, we'll tolerate a little more work.
>>>>>>> On the note of checking deep structures with nullability, we have the
>>>>>>> luxury of creating great compile time constructs such as:
>>>>>>> Given:
>>>>>>> enum Option...
>>>>>>> And assuming that Strings can never be null (remember we're in happy
>>>>>>> no-null land)
>>>>>>> typedef Foo = {
>>>>>>>    var possibleBar : Option<Bar>;   // Foo contains an optional bar
>>>>>>>    var alwaysString : String; // Shan't be null due to our
>>>>>>> awesomeness
>>>>>>> }
>>>>>>> Haxe could employ deep pattern matching on Option<Foo> like this:
>>>>>>> var optionalFoo : Option<Foo> = ...
>>>>>>> var result = match(optionalFoo) {              // much like switch
>>>>>>> but deep
>>>>>>>      some(foo(some(bar), str)) :
>>>>>>>          "foo had nonempty bar" + str;
>>>>>>>      some(foo(none, str)):
>>>>>>>           "Foo had an empty bar" + str;
>>>>>>>      none:
>>>>>>>           "didn't even have a foo !";
>>>>>>> }
>>>>>>> I maybe didn't get the syntax right, but something like that could be
>>>>>>> quite easy to manage. If you don't like it, please suggest something that is
>>>>>>> more compact, and equally expressive.
>>>>>>> Notice how, we KNOW that the string concatenation could never fail
>>>>>>> (assuming concat of null string fails - which it SHOULD IMHO). The important
>>>>>>> thing is that I never had to check on the nullness of the string because I
>>>>>>> know the compiler enforced it already.
>>>>>>> The same thing could easily be applied to multitypes.
>>>>>>> The multitypes (as proposed) seem to just be sugar for automatically
>>>>>>> creating an enum. I like haxe enums (except for the ability to null out
>>>>>>> things in an Option<> enum (which we'll hopefully get rid of by
>>>>>>> my proposition)), and I like the proposal for multitypes because they make
>>>>>>> enums more convenient.
>>>>>>> Nicolas, if you're still tuning into this, how can I get started?
>>>>>>> I'd like to implement the following:
>>>>>>> 1. A deep (comprehensive -fails when I don't cover all cases) pattern
>>>>>>> matching system.
>>>>>>> 2. Eliminating the null keyword, and making the bridge between haxe
>>>>>>> code that has nulls, as well as platform calls (using multitypes?)
>>>>>>> 3. (Secret third option: Awesome multitypes) See below:
>>>>>>> ->ML lets you name what we are calling multitypes, You can say
>>>>>>> typedef Automobile = Car | Motocycle; (that would be cool because then you
>>>>>>> could have other multitypes inside of multitypes:
>>>>>>> typedef TransportMethod = Automobile | Run | Bike (where automobile
>>>>>>> is already a multitype.
>>>>>>> -> Deep multitype definitions. The previous could be expressed as:
>>>>>>>  typedef TransportMethod = (Car | MotorCycle) | Run | Bike
>>>>>>> Look how powerful that single line is.
>>>>>>> -> Deep pattern matching, as explained before. There's a great
>>>>>>> pattern matching macro, but I do not believe it does comprehensive checks,
>>>>>>> and redundancy checks like ML tries hard to do.
>>>>>>>
>>>>>>>
>>>>>>> On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> True, although if you're using Stax, you should use toOption(),
>>>>>>>> e.g.:
>>>>>>>>
>>>>>>>> null.toOption();
>>>>>>>>
>>>>>>>> Or:
>>>>>>>>
>>>>>>>> possiblyNullValue.toOption();
>>>>>>>>
>>>>>>>> This will ensure you don't ever have to deal with nulls.
>>>>>>>> Regards,
>>>>>>>> John A. De Goes
>>>>>>>> Twitter: @jdegoes
>>>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>>>> On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:
>>>>>>>>
>>>>>>>> Yes, nullability is a big problem.
>>>>>>>>
>>>>>>>> Let's take this code for example:
>>>>>>>>
>>>>>>>> enum Option<T> {
>>>>>>>>     Some(a:T);
>>>>>>>>     None;
>>>>>>>> }
>>>>>>>>
>>>>>>>> var opt = Some(null); // legal code and passing null to an enum
>>>>>>>> constructor can't even be checked inside of the constructor.
>>>>>>>>
>>>>>>>> Am 20.01.2011 07:53, schrieb Jordo Odroj:
>>>>>>>>
>>>>>>>> There are many ways to go about this. After thinking about it for a
>>>>>>>> while, it makes sense to employ the convention that any result from another
>>>>>>>> platform must be multityped with Null. This seems pretty simple to make a
>>>>>>>> compiler option for. (I trivialize the matter, but here is the high level
>>>>>>>> description of how we can go about integrating with platforms)
>>>>>>>> Also, any library that was written under the assumption that Null
>>>>>>>> *SHOULD* be a subtype of any other object reference, we could do the same
>>>>>>>> thing for.
>>>>>>>>
>>>>>>>> The haxe compiler would have something like:
>>>>>>>> if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I
>>>>>>>> propose
>>>>>>>>      // null is not a valid keyword anywhere,
>>>>>>>>      // all objects coming from other platforms must be multityped
>>>>>>>> with Null
>>>>>>>>      // for all libraries that are not written in this special mode,
>>>>>>>> enforce that their return values must be received as multityped with Null
>>>>>>>> } else {
>>>>>>>>     // procede as current
>>>>>>>> }
>>>>>>>>
>>>>>>>> The two challenges are integrating with platforms, and preexisting
>>>>>>>> libraries. Both of which seem pretty straightforward to at least *describe*
>>>>>>>> at a high level. The implementation could be very difficult. I only have a
>>>>>>>> bit of ML experience, but I can take a stab at this if someone would
>>>>>>>> implement multitypes, and point me in the right direction. In my opinion,
>>>>>>>> haxe is at it's infant stages. I want this language to succeed, because I
>>>>>>>> acknowledge that it hits all the right marks for the current state of web
>>>>>>>> and mobile technology.
>>>>>>>> (Note, I'm not assuming that multitypes are the absolute best
>>>>>>>> solution, I'm willing to hear what other's favorites are but the general
>>>>>>>> concept should be the same as far as integrating this with other code):
>>>>>>>>
>>>>>>>> If you need further convincing, you can consider the opinion of the
>>>>>>>> original "inventor" of null:
>>>>>>>> " I call it my billion-dollar mistake. It was the invention of the
>>>>>>>> null reference in 1965. At that time, I was designing the first
>>>>>>>> comprehensive type system for references in an object oriented language
>>>>>>>> (ALGOL W). My goal was to ensure that all use of references should be
>>>>>>>> absolutely safe, with checking performed automatically by the compiler. But
>>>>>>>> I couldn't resist the temptation to put in a null reference, simply because
>>>>>>>> it was so easy to implement. This has led to innumerable errors,
>>>>>>>> vulnerabilities, and system crashes, which have probably caused a billion
>>>>>>>> dollars of pain and damage in the last forty years."
>>>>>>>> C.A.R. Hoare
>>>>>>>> We have the *luxury* of being in the beginning stages of haxe. Note
>>>>>>>> that by "beginning stages" I don't mean that haxe is underdeveloped, but
>>>>>>>> that I see huge possibilities for it. Eliminating null is going to be a
>>>>>>>> great step in this direction.
>>>>>>>> Jordo
>>>>>>>> On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> My not employ ML style pattern matching that allows you to express
>>>>>>>>> structural depth quite easilly? I recalled using them years ago and they
>>>>>>>>> were quite powerful.
>>>>>>>>>
>>>>>>>>> On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]>
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> That's not a good solution. Scala allows arbitrary switching on
>>>>>>>>>> value types. So, for example, you can write:
>>>>>>>>>>
>>>>>>>>>> val x = y match { case foo: Foo => 1 }
>>>>>>>>>>
>>>>>>>>>> This is more difficult in HaXe because the "has type" operator ":"
>>>>>>>>>> is overloaded with another meaning inside case expressions. Still, it should
>>>>>>>>>> be possible to parse something like:
>>>>>>>>>>
>>>>>>>>>> var x = switch(y) {
>>>>>>>>>>   case foo: Foo: 1
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> This code would work with any "y", even if not a multitype. Then,
>>>>>>>>>> when multitypes are added, no special feature or unique syntax needs to be
>>>>>>>>>> introduced in order to deal with them:
>>>>>>>>>>
>>>>>>>>>> var y: Int | String = "foo";
>>>>>>>>>> var x = switch(y) {
>>>>>>>>>>   case anyInt: Int: Std.string(anyInt);
>>>>>>>>>>   case anyString: String: anyString;
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> Regards,
>>>>>>>>>> John A. De Goes
>>>>>>>>>> Twitter: @jdegoes
>>>>>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>>>>>> On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:
>>>>>>>>>>
>>>>>>>>>> Hi, I find this mutliType feature amazing, and I agree with Jordo
>>>>>>>>>> on the null thing,
>>>>>>>>>> I'm just willing to ask about the syntax you're employing, I've
>>>>>>>>>> seen foo( x : A|B ) and foo( T : A|B )
>>>>>>>>>> what is the reflexion beyond that syntax ?
>>>>>>>>>> I'm a little afraid of having to do unclear things to handle that
>>>>>>>>>> feature such as the given example
>>>>>>>>>> function foo( x : A|B) {
>>>>>>>>>>     switch( x ) {
>>>>>>>>>>         case A : //
>>>>>>>>>>         case B : //
>>>>>>>>>>     }
>>>>>>>>>> }
>>>>>>>>>> It doesn't seems clear that we are talking about type in this
>>>>>>>>>> switch-case, and what if I would like to actually switch on that value ?
>>>>>>>>>> Could it be a more like defining a pseudo Type, like
>>>>>>>>>> function foo( x : T(Int|String) ) {
>>>>>>>>>>     switch ( T ) {
>>>>>>>>>>         case Int :
>>>>>>>>>>                         switch ( x ) {
>>>>>>>>>>                                 case 1 : //
>>>>>>>>>>                                 case 2 : //
>>>>>>>>>>                         }
>>>>>>>>>>         case String :
>>>>>>>>>>                         foo( Std.parseInt( x ) ) ;
>>>>>>>>>> }
>>>>>>>>>> that's just some thoughts,
>>>>>>>>>>
>>>>>>>>>> Renaud
>>>>>>>>>> From: Jordo Odroj
>>>>>>>>>> Sent: Monday, January 17, 2011 12:22 PM
>>>>>>>>>> To: The haXe compiler list
>>>>>>>>>> Subject: Re: [haXe] Eliminating the ability to have Null.
>>>>>>>>>> Oh, and I've never got the chance to thank you, Nicolas, for your
>>>>>>>>>> awesome and, quite frankly, elegant invention Haxe. I really don't even know
>>>>>>>>>> how to show my thanks. It's been nothing but a joy to be working with Haxe.
>>>>>>>>>> The request to eliminate null, is merely an attempt to take care
>>>>>>>>>> of the one remaining language feature that I consider to be "impure".
>>>>>>>>>> With "untyped" and Dynamic, you (the programmer) declare that you
>>>>>>>>>> wish to break type safety, and otherwise the experience is very pure.
>>>>>>>>>> However, null is this evil concept that breaks the type system "on your
>>>>>>>>>> behalf" without ever asking you, and without you ever indicating that it
>>>>>>>>>> should. It's the only inconsistency that I've found in the language so far.
>>>>>>>>>> Thanks again.
>>>>>>>>>>
>>>>>>>>>> On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]>
>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>> Nicolas, the longer we wait, the harder it will be. If we had
>>>>>>>>>>> multitypes, it wouldn't even have to be Null<ClassName> It would just be:
>>>>>>>>>>> var x = function (x: MyClass | Null) {
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>> If you know that a platform api could return null, then you
>>>>>>>>>>> define the haxe bindings *at the bridge point into the other platform* such
>>>>>>>>>>> that all things that could return null, return Null | TheOtherType. Then,
>>>>>>>>>>> you keep all things pure in haxe land. If anything returns null from another
>>>>>>>>>>> platform api (php etc) when the bindings did *not* indicate Null |
>>>>>>>>>>> Othertype, then that is a runtime system failure. Then we can switch on a
>>>>>>>>>>> compiler mode, where any reference to null is a compiler error (in haxe
>>>>>>>>>>> code). Any api into another platform that comes back null, without defining
>>>>>>>>>>> the return type from the platform api to be Null | OtherType would be a
>>>>>>>>>>> runtime failure. Because, let's face it, you should know the api's well
>>>>>>>>>>> enough to be able to indicate whether or not they return null anyways, so
>>>>>>>>>>> it's not unreasonable to require that a developer indicate this in the
>>>>>>>>>>> platform api's return type. In fact, once we document it, we'll save them
>>>>>>>>>>> much trouble later on.
>>>>>>>>>>> I think we could do this. Nicolas, I only have a little ML
>>>>>>>>>>> experience, but do you think it would be reasonable for me to implement
>>>>>>>>>>> this?
>>>>>>>>>>> As someone who write OCaml, Nicolas, I was hoping you would
>>>>>>>>>>> appreciate where I am coming from. The stronger the typing the less errors
>>>>>>>>>>> we experience in production, and this saves us all time, money, and stress.
>>>>>>>>>>> This is one of those things, where if you never knew you could
>>>>>>>>>>> have it, you'd never long for it, but once you try it, you'll never want to
>>>>>>>>>>> go back.
>>>>>>>>>>> Jordo
>>>>>>>>>>> On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse
>>>>>>>>>>> <[hidden email]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Le 17/01/2011 08:14, Jordo Odroj a écrit :
>>>>>>>>>>>>>
>>>>>>>>>>>>> Hello,
>>>>>>>>>>>>>
>>>>>>>>>>>>> I've always found that having the option to set an object's
>>>>>>>>>>>>> value to
>>>>>>>>>>>>> null is the worst feature of virtually every single language
>>>>>>>>>>>>> in existence. Why can't we have the haxe language support None
>>>>>>>>>>>>> |
>>>>>>>>>>>>> Some<Type> instead?
>>>>>>>>>>>>
>>>>>>>>>>>> The issue is not the language itself, since it's not that much
>>>>>>>>>>>> hard to enforce not-nullness of class members - it still requires some
>>>>>>>>>>>> extensive analysis of class constructor call.
>>>>>>>>>>>>
>>>>>>>>>>>> The main issue is that many platform API have not been designed
>>>>>>>>>>>> with such feature in mind, and that would require the developer to either
>>>>>>>>>>>> propagates Null<Foo> types or add == null checks in many places.
>>>>>>>>>>>>
>>>>>>>>>>>> I might at some point in the future make some experiments with
>>>>>>>>>>>> this, but it's not high priority.
>>>>>>>>>>>>
>>>>>>>>>>>> Nicolas
>>>>>>>>>>>>
>>>>>>>>>>>> --
>>>>>>>>>>>> haXe - an open source web programming language
>>>>>>>>>>>> http://haxe.org
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> ________________________________
>>>>>>>>>> --
>>>>>>>>>> haXe - an open source web programming language
>>>>>>>>>> http://haxe.org
>>>>>>>>>> --
>>>>>>>>>> haXe - an open source web programming language
>>>>>>>>>> http://haxe.org
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> haXe - an open source web programming language
>>>>>>>>>> http://haxe.org
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> haXe - an open source web programming language
>>>>>>>> http://haxe.org
>>>>>>>>
>>>>>>>> --
>>>>>>>> haXe - an open source web programming language
>>>>>>>> http://haxe.org
>>>>>>>
>>>>>>> --
>>>>>>> haXe - an open source web programming language
>>>>>>> http://haxe.org
>>>>>>>
>>>>>>> --
>>>>>>> haXe - an open source web programming language
>>>>>>> http://haxe.org
>>>>>>
>>>>>> --
>>>>>> haXe - an open source web programming language
>>>>>> http://haxe.org
>>>>>>
>>>>>> --
>>>>>> haXe - an open source web programming language
>>>>>> http://haxe.org
>>>>>
>>>>>
>>>>> --
>>>>> haXe - an open source web programming language
>>>>> http://haxe.org
>>>>
>>>>
>>>> --
>>>> haXe - an open source web programming language
>>>> http://haxe.org
>>>
>>>
>>> --
>>> haXe - an open source web programming language
>>> http://haxe.org
>>
>>
>> --
>> haXe - an open source web programming language
>> http://haxe.org
>
>
> --
> haXe - an open source web programming language
> http://haxe.org
>

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Tarwin Stroh-Spijer
Yeah, Flash is a **** (really naughty boy) when it comes to handling of memory. When writing games you end up wishing that you had to handle the memory manually because it can be impossible to simply restart a level (for example). So yes, in Flash especially you're nulling things all the time!

I don't have a lot of experience with the CPP one but as far as I know it's similar at least. One thing you could do is some extend the way Flash works with the base objects and have a forced destroy or some thing?

Anyway - there's a good arguement as to why we won't have no nulls ...


Tarwin Stroh-Spijer
_______________________

Touch My Pixel
http://www.touchmypixel.com/
phone: +61 3 8060 5321
_______________________


On Mon, Jan 24, 2011 at 8:56 PM, Robin Palotai <[hidden email]> wrote:
I did not confirm myself, but read that the Flash gc can be really bad-behaved:
1) It doesn't necessarily resolve cyclic dependencies (maybe the
language standard doesn't require it explicitly, but writing out of
memory here)
2) More suprisingly, some found that it may not release non-cyclic
islands which are "big enough".

Therefore hand-nulling things in the Flash environment could be an
active practice.

Robin

On Mon, Jan 24, 2011 at 10:21 AM, Jordo Odroj <[hidden email]> wrote:
> Correct me if I'm wrong, but there are only a few cases where you need
> to explicitly tell the garbage collector to free an object in a managed
> environment. One example, is if you're managing a data structure such as a
> queue. The queue is typically implemented with a fixed pool of memory, of
> which we use as much as we need and grow the pool if we need to. The easiest
> way to "pop" off of the queue is to null out the last element and keep track
> of where the new last element is. These types of cases are quite rare.
> Usually, (not as in our queue case), no references to an object - and
> needing to be garbage collected are equivalent.
> But in this case:
> 1. I would have the data structure implementation have a fixed pool of Null
> | ElementType. Or you can typedef NullableElement = Null | ElementType.
> 2. When you need to indicate that something should be garbage collected, set
> the cell to null (which is of type Null). Just the same as you're used to,
> and it's actually no extra work because you've told the system that the
> buffer holds Null | ElementType.
> 3. Now here's where the real meaty question happens. What is the interface
> to your queue? Is it Queue<ElementType> or Queue<Null | ElementType>?
> In the later case, the solution is easy. There is no additional work.  Just
> return what is in the cell that you dequeue from. In the first case,
> if someone dequeues something, and the contents of what you're about to
> dequeue is Null (instead of type ElementType) that is an indication that you
> have a programming error. This is a great use case for why multitypes are
> better even in these strange edge cases. The interface looks like:
> public function dequeue() : ElementType {...}
> This needs to return an ElementType or fail. Null should never be returned
> because (in our happy little world) Null is not a subtype of ElementType.
> Now in your queue code, you HAVE to check if the result is null before
> returning something to the client, because the compiler makes you! While
> you're checking for null, and you find it, you may as well throw an
> exception as it indicates programmer error.
> Enqueueing is easy, because the user is inserting ElementType elements, and
> that happens to be a subtype of Null | ElementType.
> In summary, the gc situations rarely come up, but that's great that you
> thought of that, however, there's always a solution with multitypes that
> actually produce cleaner, shorter, and simpler code.
> On Mon, Jan 24, 2011 at 12:31 AM, Tarwin Stroh-Spijer
> <[hidden email]> wrote:
>>
>> I'm still a little confused about the garbage collection stuff. If you
>> want to be able to tell something to be able to be garbage collected at some
>> time, you're going to have to always have it multityped as Null |
>> SomethingElse right? Otherwise you'll never going to be able to compile:
>> var myX:SomethingElse = new SomethingElse(); // create
>> myX = null; // allow garbage collection
>> Regards,
>>
>>
>> Tarwin Stroh-Spijer
>> _______________________
>>
>> Touch My Pixel
>> http://www.touchmypixel.com/
>> phone: +61 3 8060 5321
>> _______________________
>>
>>
>> On Mon, Jan 24, 2011 at 7:04 PM, Jordo Odroj <[hidden email]> wrote:
>>>
>>> Tarwin Stroh-Spijer,
>>> Thanks for the open mind. I'll try to tackle each of your questions:
>>> Defaults: There are several ways to do this that could please everyone,
>>> so I won't really go deep here. The only thing to note, is that if your
>>> parameter is a multitype of Null | String, then your default value must
>>> either be an instance of Null or String.
>>> To be clarify, I am being totally misleading when I say "eliminate null".
>>> My main request is to eliminate the fact that Null is always treated as a
>>> subtype of any object reference. The result being, if something can be
>>> nullable, you need to tell us about it, you don't get it automatically. The
>>> benefit, is that the 10% of your code that actually wants to use it, is
>>> safer because you always must switch on it - which you should be doing
>>> anyways! (or else it's a compiler error) and the other 90% is shorter and
>>> cleaner because you can always assume your objects are not null.
>>> In any project, there is some hidden part of the code that assumes that
>>> data won't be null but is *wrong* about that assumption. Having to
>>> explicitly declare what can be null, completely eliminates these parts of
>>> the code, which (as the inventor of null has pointed out - has costed
>>> society billions of actual dollars, and possibly lives.)
>>> So yes, you have to switch on these parts of the code, but you *should*
>>> be doing something to this effect anyways. Also, to recap:
>>> 1. You'll only have to check/switch for nulls in a small part of your
>>> codebase, as opposed to the entire thing.
>>> 2. The parts that do check will check in such a way that is enforced by
>>> your compiler, and will catch bugs at compile time as opposed to deploy
>>> time.
>>> 3. The other side of the coin, and the best benefit, is that the other
>>> 90% of objects that can't be assigned to null, never need to be checked,
>>> resulting in a smaller, cleaner, safer code base, just as you desire.
>>> 4. So multitypes/switching doesn't make your code base more verbose. In
>>> fact it makes it more succinct!
>>> Once you try it, you will be hooked. I suggest going through ML
>>> (language) and try programming with it for a weekend. You'll be amazed at
>>> how helpful the type system can be at compilation time.
>>> Garbage Collection: No worries here. This is mostly compilation time
>>> assistance that reduces to almost the same exact code as if you were to
>>> assign nulls to object references. The only differences is that we'd like
>>> the compiler to help us out to make sure we're doing it right, so we can
>>> have a smaller, safer code base.
>>> On Sun, Jan 23, 2011 at 10:54 PM, Tarwin Stroh-Spijer
>>> <[hidden email]> wrote:
>>>>
>>>> Hi,
>>>> Sorry to keep this going but I'd like to understand exactly WHY nulls
>>>> are bad. I have some understanding that they can create confusion / errors
>>>> because a program / function might be written that is expecting an object /
>>>> value but gets null and this cannot be caught by the compiler as nulls are
>>>> allowed.
>>>> What other problems do you get? How do you specify default parameters if
>>>> you cannot pass in null into a function? Would you have a default keyword
>>>> like in switch ?
>>>> ie:
>>>> function doMyThing(?x:Int = 10, ?y:Int = 10){}
>>>> doMyThing(null, 20);
>>>>
>>>> How would the garbage collector work without null values? How would you
>>>> remove an object reference? You'd need another keyword / type such as "var
>>>> myObj = none;" would you not?
>>>> I understand where multitypes would be good, especially in letting
>>>> people use, or not use, nulls. What other problems do they introduce though?
>>>> Does it mean you have to use a switch on any variable that uses a multitype
>>>> and you end up writing your code surrounded by a whole load of these switch
>>>> statements?
>>>> Thanks for the examples of how you might use this with Option, Short
>>>> Lambas or Monadic shorthand. The first two, Option and Short Lambas look
>>>> pretty messy to me / don't make sense to me. I guess I don't quite get what
>>>> they're doing but just from a code understandability point they look messy.
>>>> The Monadic example looks nice and neat, though truth to tell I still don't
>>>> understand the point of Monads even after reading heaps of articles / intros
>>>> on them. If you could explain what your Monad is doing that'd be helpful.
>>>> I think one of the points of haxe is to keep the language as clean as
>>>> possible. The least amount of unneeded sugar, so you can learn fast, get
>>>> started fast and build from there. It also makes code readable, and I'm sure
>>>> it makes making cross platform, well performing code, work well as well.
>>>> Regards,
>>>>
>>>> Tarwin Stroh-Spijer
>>>> _______________________
>>>>
>>>> Touch My Pixel
>>>> http://www.touchmypixel.com/
>>>> phone: +61 3 8060 5321
>>>> _______________________
>>>>
>>>>
>>>> On Sat, Jan 22, 2011 at 7:14 AM, Jordo Odroj <[hidden email]> wrote:
>>>>>
>>>>> I hope you're wrong too. :)  But I don't think that he would mind us
>>>>> implementing an optional mode that eliminates (the Null type being a subtype
>>>>> of any object reference), if he would be so kind as to point us in the right
>>>>> direction.
>>>>> If the objections are that it's harder to work with
>>>>> platforms/preexisting code, I thought that we outlined a few various
>>>>> reasonable migration strategies.
>>>>>
>>>>> On Fri, Jan 21, 2011 at 6:50 AM, John A. De Goes <[hidden email]>
>>>>> wrote:
>>>>>>
>>>>>> I agree with you, but I've talked with Nicolas before about
>>>>>> nullability, and he favors weaker restrictions than I do. So I don't think
>>>>>> HaXe will ever support either built-in Option/Maybe or nullable type system
>>>>>> (I'm happy if I'm wrong).
>>>>>> Regards,
>>>>>> John A. De Goes
>>>>>> Twitter: @jdegoes
>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>> On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:
>>>>>>
>>>>>> Like I said, I like your toOption method and I'll even experiment with
>>>>>> it. But it's not a solution, just a way to work with what's already there in
>>>>>> a safer maner. I want more help from the compiler, in that you I don't even
>>>>>> want a single null to ever accidentally leak into my program. I want to make
>>>>>> it impossible to compile the following code:
>>>>>> x = Some(something);
>>>>>> where something is capable of being null.
>>>>>> That means that all data coming from an older api, or a platform,
>>>>>> *must* either be expressed as a multitype/option, *xor* fail at runtime when
>>>>>> it receives a null back from the api, as it is a system failure - in that
>>>>>> you never understood the api you're programming against.
>>>>>>
>>>>>> By the way, how did you implement the method call on null? Is it a
>>>>>> macro or something?
>>>>>>
>>>>>> On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]>
>>>>>> wrote:
>>>>>>>
>>>>>>> I am not arguing for null. Stax does not use null internally. If you
>>>>>>> deal with external interfaces, then you have to deal with null and convert
>>>>>>> it into an Option. For these cases, the "toOption()" extension method is
>>>>>>> useful.
>>>>>>> Truly, no language should have null. It's a terrible idea.
>>>>>>> Option/Maybe is a superior way to deal with the problem. A strict nullable
>>>>>>> type system is probably my second choice.
>>>>>>> Regards,
>>>>>>> John A. De Goes
>>>>>>> Twitter: @jdegoes
>>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>>> On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:
>>>>>>>
>>>>>>> John, I like it but it doesn't solve the problem.
>>>>>>> If you look at all of your code, all of the places that have object
>>>>>>> references. The places that actually take advantage of null being a subtype
>>>>>>> of object reference, is probably about 10% or less. With the other 90+%, we
>>>>>>> need the ability to reason about objects, with certainty that objects are
>>>>>>> not null. That means that you don't ever have to check if they're null,
>>>>>>> because the compiler would have caught this.
>>>>>>> So the result is, 90% of your code is more compact because you never
>>>>>>> have to check for nulls, and more safe because runtime exceptions will be
>>>>>>> thrown in fewer unanticipated locations (which sometimes prevent
>>>>>>> system/network/db resources from being cleaned up properly). For the other
>>>>>>> ten percent, the compiler *forces* you to check both options (null vs. not
>>>>>>> null).
>>>>>>> As Heinz says, even with great "Options" enums (which are a step in
>>>>>>> the right direction) you can't prevent Some(null) at compile time. Also,
>>>>>>> right now, *every* object reference possibly contains a null value. So if
>>>>>>> you really want safe code you need to always transform every object using
>>>>>>> possiblyNullValue.toOption(). The goal is that for the 90+% of the code
>>>>>>> where we don't utilize null, we don't need to do additional work, but rather
>>>>>>> for the 10% of the code that does, we'll tolerate a little more work.
>>>>>>> On the note of checking deep structures with nullability, we have the
>>>>>>> luxury of creating great compile time constructs such as:
>>>>>>> Given:
>>>>>>> enum Option...
>>>>>>> And assuming that Strings can never be null (remember we're in happy
>>>>>>> no-null land)
>>>>>>> typedef Foo = {
>>>>>>>    var possibleBar : Option<Bar>;   // Foo contains an optional bar
>>>>>>>    var alwaysString : String; // Shan't be null due to our
>>>>>>> awesomeness
>>>>>>> }
>>>>>>> Haxe could employ deep pattern matching on Option<Foo> like this:
>>>>>>> var optionalFoo : Option<Foo> = ...
>>>>>>> var result = match(optionalFoo) {              // much like switch
>>>>>>> but deep
>>>>>>>      some(foo(some(bar), str)) :
>>>>>>>          "foo had nonempty bar" + str;
>>>>>>>      some(foo(none, str)):
>>>>>>>           "Foo had an empty bar" + str;
>>>>>>>      none:
>>>>>>>           "didn't even have a foo !";
>>>>>>> }
>>>>>>> I maybe didn't get the syntax right, but something like that could be
>>>>>>> quite easy to manage. If you don't like it, please suggest something that is
>>>>>>> more compact, and equally expressive.
>>>>>>> Notice how, we KNOW that the string concatenation could never fail
>>>>>>> (assuming concat of null string fails - which it SHOULD IMHO). The important
>>>>>>> thing is that I never had to check on the nullness of the string because I
>>>>>>> know the compiler enforced it already.
>>>>>>> The same thing could easily be applied to multitypes.
>>>>>>> The multitypes (as proposed) seem to just be sugar for automatically
>>>>>>> creating an enum. I like haxe enums (except for the ability to null out
>>>>>>> things in an Option<> enum (which we'll hopefully get rid of by
>>>>>>> my proposition)), and I like the proposal for multitypes because they make
>>>>>>> enums more convenient.
>>>>>>> Nicolas, if you're still tuning into this, how can I get started?
>>>>>>> I'd like to implement the following:
>>>>>>> 1. A deep (comprehensive -fails when I don't cover all cases) pattern
>>>>>>> matching system.
>>>>>>> 2. Eliminating the null keyword, and making the bridge between haxe
>>>>>>> code that has nulls, as well as platform calls (using multitypes?)
>>>>>>> 3. (Secret third option: Awesome multitypes) See below:
>>>>>>> ->ML lets you name what we are calling multitypes, You can say
>>>>>>> typedef Automobile = Car | Motocycle; (that would be cool because then you
>>>>>>> could have other multitypes inside of multitypes:
>>>>>>> typedef TransportMethod = Automobile | Run | Bike (where automobile
>>>>>>> is already a multitype.
>>>>>>> -> Deep multitype definitions. The previous could be expressed as:
>>>>>>>  typedef TransportMethod = (Car | MotorCycle) | Run | Bike
>>>>>>> Look how powerful that single line is.
>>>>>>> -> Deep pattern matching, as explained before. There's a great
>>>>>>> pattern matching macro, but I do not believe it does comprehensive checks,
>>>>>>> and redundancy checks like ML tries hard to do.
>>>>>>>
>>>>>>>
>>>>>>> On Thu, Jan 20, 2011 at 8:05 AM, John A. De Goes <[hidden email]>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> True, although if you're using Stax, you should use toOption(),
>>>>>>>> e.g.:
>>>>>>>>
>>>>>>>> null.toOption();
>>>>>>>>
>>>>>>>> Or:
>>>>>>>>
>>>>>>>> possiblyNullValue.toOption();
>>>>>>>>
>>>>>>>> This will ensure you don't ever have to deal with nulls.
>>>>>>>> Regards,
>>>>>>>> John A. De Goes
>>>>>>>> Twitter: @jdegoes
>>>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>>>> On Jan 20, 2011, at 1:44 AM, Heinz Hölzer wrote:
>>>>>>>>
>>>>>>>> Yes, nullability is a big problem.
>>>>>>>>
>>>>>>>> Let's take this code for example:
>>>>>>>>
>>>>>>>> enum Option<T> {
>>>>>>>>     Some(a:T);
>>>>>>>>     None;
>>>>>>>> }
>>>>>>>>
>>>>>>>> var opt = Some(null); // legal code and passing null to an enum
>>>>>>>> constructor can't even be checked inside of the constructor.
>>>>>>>>
>>>>>>>> Am 20.01.2011 07:53, schrieb Jordo Odroj:
>>>>>>>>
>>>>>>>> There are many ways to go about this. After thinking about it for a
>>>>>>>> while, it makes sense to employ the convention that any result from another
>>>>>>>> platform must be multityped with Null. This seems pretty simple to make a
>>>>>>>> compiler option for. (I trivialize the matter, but here is the high level
>>>>>>>> description of how we can go about integrating with platforms)
>>>>>>>> Also, any library that was written under the assumption that Null
>>>>>>>> *SHOULD* be a subtype of any other object reference, we could do the same
>>>>>>>> thing for.
>>>>>>>>
>>>>>>>> The haxe compiler would have something like:
>>>>>>>> if (NullNotSubtypeOfObjectPoint) {  // super awesome mode that I
>>>>>>>> propose
>>>>>>>>      // null is not a valid keyword anywhere,
>>>>>>>>      // all objects coming from other platforms must be multityped
>>>>>>>> with Null
>>>>>>>>      // for all libraries that are not written in this special mode,
>>>>>>>> enforce that their return values must be received as multityped with Null
>>>>>>>> } else {
>>>>>>>>     // procede as current
>>>>>>>> }
>>>>>>>>
>>>>>>>> The two challenges are integrating with platforms, and preexisting
>>>>>>>> libraries. Both of which seem pretty straightforward to at least *describe*
>>>>>>>> at a high level. The implementation could be very difficult. I only have a
>>>>>>>> bit of ML experience, but I can take a stab at this if someone would
>>>>>>>> implement multitypes, and point me in the right direction. In my opinion,
>>>>>>>> haxe is at it's infant stages. I want this language to succeed, because I
>>>>>>>> acknowledge that it hits all the right marks for the current state of web
>>>>>>>> and mobile technology.
>>>>>>>> (Note, I'm not assuming that multitypes are the absolute best
>>>>>>>> solution, I'm willing to hear what other's favorites are but the general
>>>>>>>> concept should be the same as far as integrating this with other code):
>>>>>>>>
>>>>>>>> If you need further convincing, you can consider the opinion of the
>>>>>>>> original "inventor" of null:
>>>>>>>> " I call it my billion-dollar mistake. It was the invention of the
>>>>>>>> null reference in 1965. At that time, I was designing the first
>>>>>>>> comprehensive type system for references in an object oriented language
>>>>>>>> (ALGOL W). My goal was to ensure that all use of references should be
>>>>>>>> absolutely safe, with checking performed automatically by the compiler. But
>>>>>>>> I couldn't resist the temptation to put in a null reference, simply because
>>>>>>>> it was so easy to implement. This has led to innumerable errors,
>>>>>>>> vulnerabilities, and system crashes, which have probably caused a billion
>>>>>>>> dollars of pain and damage in the last forty years."
>>>>>>>> C.A.R. Hoare
>>>>>>>> We have the *luxury* of being in the beginning stages of haxe. Note
>>>>>>>> that by "beginning stages" I don't mean that haxe is underdeveloped, but
>>>>>>>> that I see huge possibilities for it. Eliminating null is going to be a
>>>>>>>> great step in this direction.
>>>>>>>> Jordo
>>>>>>>> On Mon, Jan 17, 2011 at 6:42 PM, Jordo Odroj <[hidden email]>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> My not employ ML style pattern matching that allows you to express
>>>>>>>>> structural depth quite easilly? I recalled using them years ago and they
>>>>>>>>> were quite powerful.
>>>>>>>>>
>>>>>>>>> On Mon, Jan 17, 2011 at 8:28 AM, John A. De Goes <[hidden email]>
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> That's not a good solution. Scala allows arbitrary switching on
>>>>>>>>>> value types. So, for example, you can write:
>>>>>>>>>>
>>>>>>>>>> val x = y match { case foo: Foo => 1 }
>>>>>>>>>>
>>>>>>>>>> This is more difficult in HaXe because the "has type" operator ":"
>>>>>>>>>> is overloaded with another meaning inside case expressions. Still, it should
>>>>>>>>>> be possible to parse something like:
>>>>>>>>>>
>>>>>>>>>> var x = switch(y) {
>>>>>>>>>>   case foo: Foo: 1
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> This code would work with any "y", even if not a multitype. Then,
>>>>>>>>>> when multitypes are added, no special feature or unique syntax needs to be
>>>>>>>>>> introduced in order to deal with them:
>>>>>>>>>>
>>>>>>>>>> var y: Int | String = "foo";
>>>>>>>>>> var x = switch(y) {
>>>>>>>>>>   case anyInt: Int: Std.string(anyInt);
>>>>>>>>>>   case anyString: String: anyString;
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> Regards,
>>>>>>>>>> John A. De Goes
>>>>>>>>>> Twitter: @jdegoes
>>>>>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>>>>>> On Jan 17, 2011, at 8:18 AM, Renaud Bardet wrote:
>>>>>>>>>>
>>>>>>>>>> Hi, I find this mutliType feature amazing, and I agree with Jordo
>>>>>>>>>> on the null thing,
>>>>>>>>>> I'm just willing to ask about the syntax you're employing, I've
>>>>>>>>>> seen foo( x : A|B ) and foo( T : A|B )
>>>>>>>>>> what is the reflexion beyond that syntax ?
>>>>>>>>>> I'm a little afraid of having to do unclear things to handle that
>>>>>>>>>> feature such as the given example
>>>>>>>>>> function foo( x : A|B) {
>>>>>>>>>>     switch( x ) {
>>>>>>>>>>         case A : //
>>>>>>>>>>         case B : //
>>>>>>>>>>     }
>>>>>>>>>> }
>>>>>>>>>> It doesn't seems clear that we are talking about type in this
>>>>>>>>>> switch-case, and what if I would like to actually switch on that value ?
>>>>>>>>>> Could it be a more like defining a pseudo Type, like
>>>>>>>>>> function foo( x : T(Int|String) ) {
>>>>>>>>>>     switch ( T ) {
>>>>>>>>>>         case Int :
>>>>>>>>>>                         switch ( x ) {
>>>>>>>>>>                                 case 1 : //
>>>>>>>>>>                                 case 2 : //
>>>>>>>>>>                         }
>>>>>>>>>>         case String :
>>>>>>>>>>                         foo( Std.parseInt( x ) ) ;
>>>>>>>>>> }
>>>>>>>>>> that's just some thoughts,
>>>>>>>>>>
>>>>>>>>>> Renaud
>>>>>>>>>> From: Jordo Odroj
>>>>>>>>>> Sent: Monday, January 17, 2011 12:22 PM
>>>>>>>>>> To: The haXe compiler list
>>>>>>>>>> Subject: Re: [haXe] Eliminating the ability to have Null.
>>>>>>>>>> Oh, and I've never got the chance to thank you, Nicolas, for your
>>>>>>>>>> awesome and, quite frankly, elegant invention Haxe. I really don't even know
>>>>>>>>>> how to show my thanks. It's been nothing but a joy to be working with Haxe.
>>>>>>>>>> The request to eliminate null, is merely an attempt to take care
>>>>>>>>>> of the one remaining language feature that I consider to be "impure".
>>>>>>>>>> With "untyped" and Dynamic, you (the programmer) declare that you
>>>>>>>>>> wish to break type safety, and otherwise the experience is very pure.
>>>>>>>>>> However, null is this evil concept that breaks the type system "on your
>>>>>>>>>> behalf" without ever asking you, and without you ever indicating that it
>>>>>>>>>> should. It's the only inconsistency that I've found in the language so far.
>>>>>>>>>> Thanks again.
>>>>>>>>>>
>>>>>>>>>> On Mon, Jan 17, 2011 at 12:42 AM, Jordo Odroj <[hidden email]>
>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>> Nicolas, the longer we wait, the harder it will be. If we had
>>>>>>>>>>> multitypes, it wouldn't even have to be Null<ClassName> It would just be:
>>>>>>>>>>> var x = function (x: MyClass | Null) {
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>> If you know that a platform api could return null, then you
>>>>>>>>>>> define the haxe bindings *at the bridge point into the other platform* such
>>>>>>>>>>> that all things that could return null, return Null | TheOtherType. Then,
>>>>>>>>>>> you keep all things pure in haxe land. If anything returns null from another
>>>>>>>>>>> platform api (php etc) when the bindings did *not* indicate Null |
>>>>>>>>>>> Othertype, then that is a runtime system failure. Then we can switch on a
>>>>>>>>>>> compiler mode, where any reference to null is a compiler error (in haxe
>>>>>>>>>>> code). Any api into another platform that comes back null, without defining
>>>>>>>>>>> the return type from the platform api to be Null | OtherType would be a
>>>>>>>>>>> runtime failure. Because, let's face it, you should know the api's well
>>>>>>>>>>> enough to be able to indicate whether or not they return null anyways, so
>>>>>>>>>>> it's not unreasonable to require that a developer indicate this in the
>>>>>>>>>>> platform api's return type. In fact, once we document it, we'll save them
>>>>>>>>>>> much trouble later on.
>>>>>>>>>>> I think we could do this. Nicolas, I only have a little ML
>>>>>>>>>>> experience, but do you think it would be reasonable for me to implement
>>>>>>>>>>> this?
>>>>>>>>>>> As someone who write OCaml, Nicolas, I was hoping you would
>>>>>>>>>>> appreciate where I am coming from. The stronger the typing the less errors
>>>>>>>>>>> we experience in production, and this saves us all time, money, and stress.
>>>>>>>>>>> This is one of those things, where if you never knew you could
>>>>>>>>>>> have it, you'd never long for it, but once you try it, you'll never want to
>>>>>>>>>>> go back.
>>>>>>>>>>> Jordo
>>>>>>>>>>> On Mon, Jan 17, 2011 at 12:32 AM, Nicolas Cannasse
>>>>>>>>>>> <[hidden email]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Le 17/01/2011 08:14, Jordo Odroj a écrit :
>>>>>>>>>>>>>
>>>>>>>>>>>>> Hello,
>>>>>>>>>>>>>
>>>>>>>>>>>>> I've always found that having the option to set an object's
>>>>>>>>>>>>> value to
>>>>>>>>>>>>> null is the worst feature of virtually every single language
>>>>>>>>>>>>> in existence. Why can't we have the haxe language support None
>>>>>>>>>>>>> |
>>>>>>>>>>>>> Some<Type> instead?
>>>>>>>>>>>>
>>>>>>>>>>>> The issue is not the language itself, since it's not that much
>>>>>>>>>>>> hard to enforce not-nullness of class members - it still requires some
>>>>>>>>>>>> extensive analysis of class constructor call.
>>>>>>>>>>>>
>>>>>>>>>>>> The main issue is that many platform API have not been designed
>>>>>>>>>>>> with such feature in mind, and that would require the developer to either
>>>>>>>>>>>> propagates Null<Foo> types or add == null checks in many places.
>>>>>>>>>>>>
>>>>>>>>>>>> I might at some point in the future make some experiments with
>>>>>>>>>>>> this, but it's not high priority.
>>>>>>>>>>>>
>>>>>>>>>>>> Nicolas
>>>>>>>>>>>>
>>>>>>>>>>>> --
>>>>>>>>>>>> haXe - an open source web programming language
>>>>>>>>>>>> http://haxe.org
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> ________________________________
>>>>>>>>>> --
>>>>>>>>>> haXe - an open source web programming language
>>>>>>>>>> http://haxe.org
>>>>>>>>>> --
>>>>>>>>>> haXe - an open source web programming language
>>>>>>>>>> http://haxe.org
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> haXe - an open source web programming language
>>>>>>>>>> http://haxe.org
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> haXe - an open source web programming language
>>>>>>>> http://haxe.org
>>>>>>>>
>>>>>>>> --
>>>>>>>> haXe - an open source web programming language
>>>>>>>> http://haxe.org
>>>>>>>
>>>>>>> --
>>>>>>> haXe - an open source web programming language
>>>>>>> http://haxe.org
>>>>>>>
>>>>>>> --
>>>>>>> haXe - an open source web programming language
>>>>>>> http://haxe.org
>>>>>>
>>>>>> --
>>>>>> haXe - an open source web programming language
>>>>>> http://haxe.org
>>>>>>
>>>>>> --
>>>>>> haXe - an open source web programming language
>>>>>> http://haxe.org
>>>>>
>>>>>
>>>>> --
>>>>> haXe - an open source web programming language
>>>>> http://haxe.org
>>>>
>>>>
>>>> --
>>>> haXe - an open source web programming language
>>>> http://haxe.org
>>>
>>>
>>> --
>>> haXe - an open source web programming language
>>> http://haxe.org
>>
>>
>> --
>> haXe - an open source web programming language
>> http://haxe.org
>
>
> --
> haXe - an open source web programming language
> http://haxe.org
>

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Eliminating the ability to have Null.

Jordo Odroj
In reply to this post by Robin Palotai
Sure, if we eliminate the fact that Null is automatically a subtype of  
every object, then you can still manually null out object references,  
but you just need to declare this object as a multitype, or make sure  
type inference is smart enough to figure it out. Actually, it would be  
great if we could infer this! :)


Sent from my mobile device

On Jan 24, 2011, at 1:56 AM, Robin Palotai <[hidden email]>  
wrote:

> I did not confirm myself, but read that the Flash gc can be really  
> bad-behaved:
> 1) It doesn't necessarily resolve cyclic dependencies (maybe the
> language standard doesn't require it explicitly, but writing out of
> memory here)
> 2) More suprisingly, some found that it may not release non-cyclic
> islands which are "big enough".
>
> Therefore hand-nulling things in the Flash environment could be an
> active practice.
>
> Robin
>
> On Mon, Jan 24, 2011 at 10:21 AM, Jordo Odroj <[hidden email]>  
> wrote:
>> Correct me if I'm wrong, but there are only a few cases where you  
>> need
>> to explicitly tell the garbage collector to free an object in a  
>> managed
>> environment. One example, is if you're managing a data structure  
>> such as a
>> queue. The queue is typically implemented with a fixed pool of  
>> memory, of
>> which we use as much as we need and grow the pool if we need to.  
>> The easiest
>> way to "pop" off of the queue is to null out the last element and  
>> keep track
>> of where the new last element is. These types of cases are quite  
>> rare.
>> Usually, (not as in our queue case), no references to an object - and
>> needing to be garbage collected are equivalent.
>> But in this case:
>> 1. I would have the data structure implementation have a fixed pool  
>> of Null
>> | ElementType. Or you can typedef NullableElement = Null |  
>> ElementType.
>> 2. When you need to indicate that something should be garbage  
>> collected, set
>> the cell to null (which is of type Null). Just the same as you're  
>> used to,
>> and it's actually no extra work because you've told the system that  
>> the
>> buffer holds Null | ElementType.
>> 3. Now here's where the real meaty question happens. What is the  
>> interface
>> to your queue? Is it Queue<ElementType> or Queue<Null | ElementType>?
>> In the later case, the solution is easy. There is no additional  
>> work.  Just
>> return what is in the cell that you dequeue from. In the first case,
>> if someone dequeues something, and the contents of what you're  
>> about to
>> dequeue is Null (instead of type ElementType) that is an indication  
>> that you
>> have a programming error. This is a great use case for why  
>> multitypes are
>> better even in these strange edge cases. The interface looks like:
>> public function dequeue() : ElementType {...}
>> This needs to return an ElementType or fail. Null should never be  
>> returned
>> because (in our happy little world) Null is not a subtype of  
>> ElementType.
>> Now in your queue code, you HAVE to check if the result is null  
>> before
>> returning something to the client, because the compiler makes you!  
>> While
>> you're checking for null, and you find it, you may as well throw an
>> exception as it indicates programmer error.
>> Enqueueing is easy, because the user is inserting ElementType  
>> elements, and
>> that happens to be a subtype of Null | ElementType.
>> In summary, the gc situations rarely come up, but that's great that  
>> you
>> thought of that, however, there's always a solution with multitypes  
>> that
>> actually produce cleaner, shorter, and simpler code.
>> On Mon, Jan 24, 2011 at 12:31 AM, Tarwin Stroh-Spijer
>> <[hidden email]> wrote:
>>>
>>> I'm still a little confused about the garbage collection stuff. If  
>>> you
>>> want to be able to tell something to be able to be garbage  
>>> collected at some
>>> time, you're going to have to always have it multityped as Null |
>>> SomethingElse right? Otherwise you'll never going to be able to  
>>> compile:
>>> var myX:SomethingElse = new SomethingElse(); // create
>>> myX = null; // allow garbage collection
>>> Regards,
>>>
>>>
>>> Tarwin Stroh-Spijer
>>> _______________________
>>>
>>> Touch My Pixel
>>> http://www.touchmypixel.com/
>>> phone: +61 3 8060 5321
>>> _______________________
>>>
>>>
>>> On Mon, Jan 24, 2011 at 7:04 PM, Jordo Odroj <[hidden email]>  
>>> wrote:
>>>>
>>>> Tarwin Stroh-Spijer,
>>>> Thanks for the open mind. I'll try to tackle each of your  
>>>> questions:
>>>> Defaults: There are several ways to do this that could please  
>>>> everyone,
>>>> so I won't really go deep here. The only thing to note, is that  
>>>> if your
>>>> parameter is a multitype of Null | String, then your default  
>>>> value must
>>>> either be an instance of Null or String.
>>>> To be clarify, I am being totally misleading when I say  
>>>> "eliminate null".
>>>> My main request is to eliminate the fact that Null is always  
>>>> treated as a
>>>> subtype of any object reference. The result being, if something  
>>>> can be
>>>> nullable, you need to tell us about it, you don't get it  
>>>> automatically. The
>>>> benefit, is that the 10% of your code that actually wants to use  
>>>> it, is
>>>> safer because you always must switch on it - which you should be  
>>>> doing
>>>> anyways! (or else it's a compiler error) and the other 90% is  
>>>> shorter and
>>>> cleaner because you can always assume your objects are not null.
>>>> In any project, there is some hidden part of the code that  
>>>> assumes that
>>>> data won't be null but is *wrong* about that assumption. Having to
>>>> explicitly declare what can be null, completely eliminates these  
>>>> parts of
>>>> the code, which (as the inventor of null has pointed out - has  
>>>> costed
>>>> society billions of actual dollars, and possibly lives.)
>>>> So yes, you have to switch on these parts of the code, but you  
>>>> *should*
>>>> be doing something to this effect anyways. Also, to recap:
>>>> 1. You'll only have to check/switch for nulls in a small part of  
>>>> your
>>>> codebase, as opposed to the entire thing.
>>>> 2. The parts that do check will check in such a way that is  
>>>> enforced by
>>>> your compiler, and will catch bugs at compile time as opposed to  
>>>> deploy
>>>> time.
>>>> 3. The other side of the coin, and the best benefit, is that the  
>>>> other
>>>> 90% of objects that can't be assigned to null, never need to be  
>>>> checked,
>>>> resulting in a smaller, cleaner, safer code base, just as you  
>>>> desire.
>>>> 4. So multitypes/switching doesn't make your code base more  
>>>> verbose. In
>>>> fact it makes it more succinct!
>>>> Once you try it, you will be hooked. I suggest going through ML
>>>> (language) and try programming with it for a weekend. You'll be  
>>>> amazed at
>>>> how helpful the type system can be at compilation time.
>>>> Garbage Collection: No worries here. This is mostly compilation  
>>>> time
>>>> assistance that reduces to almost the same exact code as if you  
>>>> were to
>>>> assign nulls to object references. The only differences is that  
>>>> we'd like
>>>> the compiler to help us out to make sure we're doing it right, so  
>>>> we can
>>>> have a smaller, safer code base.
>>>> On Sun, Jan 23, 2011 at 10:54 PM, Tarwin Stroh-Spijer
>>>> <[hidden email]> wrote:
>>>>>
>>>>> Hi,
>>>>> Sorry to keep this going but I'd like to understand exactly WHY  
>>>>> nulls
>>>>> are bad. I have some understanding that they can create  
>>>>> confusion / errors
>>>>> because a program / function might be written that is expecting  
>>>>> an object /
>>>>> value but gets null and this cannot be caught by the compiler as  
>>>>> nulls are
>>>>> allowed.
>>>>> What other problems do you get? How do you specify default  
>>>>> parameters if
>>>>> you cannot pass in null into a function? Would you have a  
>>>>> default keyword
>>>>> like in switch ?
>>>>> ie:
>>>>> function doMyThing(?x:Int = 10, ?y:Int = 10){}
>>>>> doMyThing(null, 20);
>>>>>
>>>>> How would the garbage collector work without null values? How  
>>>>> would you
>>>>> remove an object reference? You'd need another keyword / type  
>>>>> such as "var
>>>>> myObj = none;" would you not?
>>>>> I understand where multitypes would be good, especially in letting
>>>>> people use, or not use, nulls. What other problems do they  
>>>>> introduce though?
>>>>> Does it mean you have to use a switch on any variable that uses  
>>>>> a multitype
>>>>> and you end up writing your code surrounded by a whole load of  
>>>>> these switch
>>>>> statements?
>>>>> Thanks for the examples of how you might use this with Option,  
>>>>> Short
>>>>> Lambas or Monadic shorthand. The first two, Option and Short  
>>>>> Lambas look
>>>>> pretty messy to me / don't make sense to me. I guess I don't  
>>>>> quite get what
>>>>> they're doing but just from a code understandability point they  
>>>>> look messy.
>>>>> The Monadic example looks nice and neat, though truth to tell I  
>>>>> still don't
>>>>> understand the point of Monads even after reading heaps of  
>>>>> articles / intros
>>>>> on them. If you could explain what your Monad is doing that'd be  
>>>>> helpful.
>>>>> I think one of the points of haxe is to keep the language as  
>>>>> clean as
>>>>> possible. The least amount of unneeded sugar, so you can learn  
>>>>> fast, get
>>>>> started fast and build from there. It also makes code readable,  
>>>>> and I'm sure
>>>>> it makes making cross platform, well performing code, work well  
>>>>> as well.
>>>>> Regards,
>>>>>
>>>>> Tarwin Stroh-Spijer
>>>>> _______________________
>>>>>
>>>>> Touch My Pixel
>>>>> http://www.touchmypixel.com/
>>>>> phone: +61 3 8060 5321
>>>>> _______________________
>>>>>
>>>>>
>>>>> On Sat, Jan 22, 2011 at 7:14 AM, Jordo Odroj <[hidden email]>  
>>>>> wrote:
>>>>>>
>>>>>> I hope you're wrong too. :)  But I don't think that he would  
>>>>>> mind us
>>>>>> implementing an optional mode that eliminates (the Null type  
>>>>>> being a subtype
>>>>>> of any object reference), if he would be so kind as to point us  
>>>>>> in the right
>>>>>> direction.
>>>>>> If the objections are that it's harder to work with
>>>>>> platforms/preexisting code, I thought that we outlined a few  
>>>>>> various
>>>>>> reasonable migration strategies.
>>>>>>
>>>>>> On Fri, Jan 21, 2011 at 6:50 AM, John A. De Goes <[hidden email]
>>>>>> >
>>>>>> wrote:
>>>>>>>
>>>>>>> I agree with you, but I've talked with Nicolas before about
>>>>>>> nullability, and he favors weaker restrictions than I do. So I  
>>>>>>> don't think
>>>>>>> HaXe will ever support either built-in Option/Maybe or  
>>>>>>> nullable type system
>>>>>>> (I'm happy if I'm wrong).
>>>>>>> Regards,
>>>>>>> John A. De Goes
>>>>>>> Twitter: @jdegoes
>>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>>> On Jan 20, 2011, at 11:45 PM, Jordo Odroj wrote:
>>>>>>>
>>>>>>> Like I said, I like your toOption method and I'll even  
>>>>>>> experiment with
>>>>>>> it. But it's not a solution, just a way to work with what's  
>>>>>>> already there in
>>>>>>> a safer maner. I want more help from the compiler, in that you  
>>>>>>> I don't even
>>>>>>> want a single null to ever accidentally leak into my program.  
>>>>>>> I want to make
>>>>>>> it impossible to compile the following code:
>>>>>>> x = Some(something);
>>>>>>> where something is capable of being null.
>>>>>>> That means that all data coming from an older api, or a  
>>>>>>> platform,
>>>>>>> *must* either be expressed as a multitype/option, *xor* fail  
>>>>>>> at runtime when
>>>>>>> it receives a null back from the api, as it is a system  
>>>>>>> failure - in that
>>>>>>> you never understood the api you're programming against.
>>>>>>>
>>>>>>> By the way, how did you implement the method call on null? Is  
>>>>>>> it a
>>>>>>> macro or something?
>>>>>>>
>>>>>>> On Thu, Jan 20, 2011 at 7:58 PM, John A. De Goes <[hidden email]
>>>>>>> >
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> I am not arguing for null. Stax does not use null internally.  
>>>>>>>> If you
>>>>>>>> deal with external interfaces, then you have to deal with  
>>>>>>>> null and convert
>>>>>>>> it into an Option. For these cases, the "toOption()"  
>>>>>>>> extension method is
>>>>>>>> useful.
>>>>>>>> Truly, no language should have null. It's a terrible idea.
>>>>>>>> Option/Maybe is a superior way to deal with the problem. A  
>>>>>>>> strict nullable
>>>>>>>> type system is probably my second choice.
>>>>>>>> Regards,
>>>>>>>> John A. De Goes
>>>>>>>> Twitter: @jdegoes
>>>>>>>> LinkedIn: http://linkedin.com/in/jdegoes
>>>>>>>> On Jan 20, 2011, at 7:30 PM, Jordo Odroj wrote:
>>>>>>>>
>>>>>>>> John, I like it but it doesn't solve the problem.
>>>>>>>> If you look at all of your code, all of the places that have  
>>>>>>>> object
>>>>>>>> references. The places that actually take advantage of null  
>>>>>>>> being a subtype
>>>>>>>> of object reference, is probably about 10% or less. With the  
>>>>>>>> other 90+%, we
>>>>>>>> need the ability to reason about objects, with certainty that  
>>>>>>>> objects are
>>>>>>>> not null. That means that you don't ever have to check if  
>>>>>>>> they're null,
>>>>>>>> because the compiler would have caught this.
>>>>>>>> So the result is, 90% of your code is more compact because  
>>>>>>>> you never
>>>>>>>> have to check for nulls, and more safe because runtime  
>>>>>>>> exceptions will be
>>>>>>>> thrown in fewer unanticipated locations (which sometimes  
>>>>>>>> prevent
>>>>>>>> system/network/db resources from being cleaned up properly).  
>>>>>>>> For the other
>>>>>>>> ten percent, the compiler *forces* you to check both options  
>>>>>>>> (null vs. not
>>>>>>>> null).
>>>>>>>> As Heinz says, even with great "Options" enums (which are a  
>>>>>>>> step in
>>>>>>>> the right direction) you can't prevent Some(null) at compile  
>>>>>>>> time. Also,
>>>>>>>> right now, *every* object reference possibly contains a null  
>>>>>>>> value. So if
>>>>>>>> you really want safe code you need to always transform every  
>>>>>>>> object using
>>>>>>>> possiblyNullValue.toOption(). The goal is that for the 90+%  
>>>>>>>> of the code
>>>>>>>> where we don't utilize null, we don't need to do additional  
>>>>>>>> work, but rather
>>>>>>>> for the 10% of the code that does, we'll tolerate a little  
>>>>>>>> more work.
>>>>>>>> On the note of checking deep structures with nullability, we  
>>>>>>>> have the
>>>>>>>> luxury of creating great compile time constructs such as:
>>>>>>>> Given:
>>>>>>>> enum Option...
>>>>>>>> And assuming that Strings can never be null (remember we're  
>>>>>>>> in happy
>>>>>>>> no-null land)
>>>>>>>> typedef Foo = {
>>>>>>>>    var possibleBar : Option<Bar>;   // Foo contains an  
>>>>>>>> optional bar
>>>>>>>>    var alwaysString : String; // Shan't be null due to our
>>>>>>>> awesomeness
>>>>>>>> }
>>>>>>>> Haxe could employ deep pattern matching on Option<Foo> like  
>>>>>>>> this:
>>>>>>>> var optionalFoo : Option<Foo> = ...
>>>>>>>> var result = match(optionalFoo) {              // much like  
>>>>>>>> switch
>>>>>>>> but deep
>>>>>>>>      some(foo(some(bar), str)) :
>>>>>>>>          "foo had nonempty bar" + str;
>>>>>>>>      some(foo(none, str)):
>>>>>>>>           "Foo had an empty bar" + str;
>>>>>>>>      none:
>>>>>>>>           "didn't even have a foo !";
>>>>>>>> }
>>>>>>>> I maybe didn't get the syntax right, but something like that  
>>>>>>>> could be
>>>>>>>> quite easy to manage. If you don't like it, please suggest  
>>>>>>>> something that is
>>>>>>>> more compact, and equally expressive.
>>>>>>>> Notice how, we KNOW that the string concatenation could never  
>>>>>>>> fail
>>>>>>>> (assuming concat of null string fails - which it SHOULD  
>>>>>>>> IMHO). The important
>>>>>>>> thing is that I never had to check on the nullness of the  
>>>>>>>> string because I
>>>>>>>> know the compiler enforced it already.
>>>>>>>> The same thing could easily be applied to multitypes.
>>>>>>>> The multitypes (as proposed) seem to just be sugar for  
>>>>>>>> automatically
>>>>>>>> creating an enum. I like haxe enums (except for the ability  
>>>>>>>> to null out
>>>>>>>> things in an Option<> enum (which we'll hopefully get rid of by
>>>>>>>> my proposition)), and I like the proposal for multitypes  
>>>>>>>> because they make
>>>>>>>> enums more convenient.
>>>>>>>> Nicolas, if you're still tuning into this, how can I get  
>>>>>>>> started?
>>>>>>>> I'd like to implement the following:
>>>>>>>> 1. A deep (comprehensive -fails when I don't cover all cases)  
>>>>>>>> pattern
>>>>>>>> matching system.
>>>>>>>> 2. Eliminating the null keyword, and making the bridge  
>>>>>>>> between haxe
>>>>>>>> code that has nulls, as well as platform calls (using  
>>>>>>>> multitypes?)
>>>>>>>> 3. (Secret third option: Awesome multitypes) See below:
>>>>>>>> ->ML lets you name what we are calling multitypes, You can say
>>>>>>>> typedef Automobile = Car | Motocycle; (that would be cool  
>>>>>>>> because then you
>>>>>>>> could have other multitypes inside of multitypes:
>>>>>>>> typedef TransportMethod = Automobile | Run | Bike (where  
>>>>>>>> automobile
>>>>>>>> is already a multitype.
>>>>>>>> -> Deep multitype definitions. The previous could be  
>>>>>>>> expressed as:
>>>>>>>>  typedef TransportMethod = (Car | MotorCycle) | Run | Bike
>>>>>>>> Look how powerful that single line is.
>>>>>>>> -> Deep pattern matching, as explained before. There's a great
>>>>>>>> pattern matching macro, but I

--
haXe - an open source web programming language
http://haxe.org
12