September 27, 2009
On 27-9-2009 9:20, Walter Bright wrote:
> language_fan wrote:
>> The idea behind non-nullable types and other contracts is to catch
>> these errors on compile time. Sure, the code is a bit harder to write,
>> but it is safe and never segfaults. The idea is to minimize the amount
>> of runtime errors of all sorts. That's also how other features of
>> statically typed languages work.
>
>
> I certainly agree that catching errors at compile time is preferable by
> far. Where I disagree is the notion that non-nullable types achieve
> this. I've argued extensively here that they hide errors, not fix them.
>
> Also, by "safe" I presume you mean "memory safe" which means free of
> memory corruption. Null pointer exceptions are memory safe. A null
> pointer could be caused by memory corruption, but it cannot *cause*
> memory corruption.

// t.d
void main()
{
   int* a;
   a[20000] = 2;
}

[C:\Users\Lionello] dmd -run t.d

[C:\Users\Lionello]

This code passes on Vista. Granted, needs a big enough offset and some luck, but indexing null will never be secure in the current flat memory models.

L.
September 28, 2009
Lutger:

> First, there is a huge demand for programmers, so much that even I got hired in this time of crisis ;) Good programmers don't suddenly fall from the skies apparently.

This is the nicest thing I've read this week. Thank you very much :-) Biologists aren't that lucky, apparently.

Bye,
bearophile
September 28, 2009
"Jeremie Pelletier" <jeremiep@gmail.com> wrote in message news:h9mmre$1i8j$1@digitalmars.com...
> Ary Borenszweig wrote:
>>
>> Object is not-nullable, Object? (or whatever syntax you like) is nullable. So that line is a compile-time error: you can't cast a null to an Object (because Object *can't* be null).
>>
>
> union A {
> Object foo;
> Object? bar;
> }
>
> Give me a type system, and I will find backdoors :)
>

Unions are nothing more than an alternate syntax for a reinterpret cast. And it's an arguably worse syntax because unlike casts, uses of it are indistinguishable from normal safe code, there's nothing to grep for. As such, unions should never be considered any more safe than cast(x)y. The following is just as dangerous as your example above and doesn't even touch the issue of nullability/non-nulability:

union A {
int foo;
float bar;
}


September 28, 2009
On Mon, 28 Sep 2009 01:31:44 +0400, Jeremie Pelletier <jeremiep@gmail.com> wrote:

> Andrei Alexandrescu wrote:
>> Jeremie Pelletier wrote:
>>>> Is this Linux specific? what about other *nix systems, like BSD and solaris?
>>>
>>> Signal handler are standard to most *nix platforms since they're part of the posix C standard libraries, maybe some platforms will require a special handling but nothing impossible to do.
>>  Let me write a message on behalf of Sean Kelly. He wrote that to Walter and myself this morning, then I suggested him to post it but probably he is off email for a short while. Hopefully the community will find a solution to the issue he's raising. Let me post this:
>>  ===================
>> Sean Kelly wrote:
>>  There's one minor problem with his code.  It's not safe to throw an exception from a signal handler.  Here's a quote from the POSIX spec at opengroup.org:
>>  "In order to prevent errors arising from interrupting non-reentrant function calls, applications should protect calls to these functions either by blocking the appropriate signals or through the use of some programmatic semaphore (see semget() , sem_init() , sem_open() , and so on). Note in particular that even the "safe" functions may modify errno; the signal-catching function, if not executing as an independent thread, may want to save and restore its value. Naturally, the same principles apply to the reentrancy of application routines and asynchronous data access. Note thatlongjmp() and siglongjmp() are not in the list of reentrant functions. This is because the code executing after longjmp() and siglongjmp() can call any unsafe functions with the same danger as calling those unsafe functions directly from the signal handler. Applications that use longjmp() andsiglongjmp() from within signal handlers require rigorous protection in order to be portable."
>>  If this were an acceptable approach it would have been in druntime ages ago :-)
>> ===================
>>    Andrei
>
> Yes but the segfault signal handler is not made to design code that can live with these exceptions, its just a feature to allow segfaults to be sent to the crash handler to get a backtrace dump. Even on windows while you can recover from access violations, its generally a bad idea to allow for bugs to be turned into features.
>
> Jeremie

Isn't this reason alone strong enough to encourage use of non-null references?
And to implement them, since we don't the feature currently.
September 28, 2009
Lionello Lunesu wrote:

> On 27-9-2009 9:20, Walter Bright wrote:
>> language_fan wrote:
>>> The idea behind non-nullable types and other contracts is to catch these errors on compile time. Sure, the code is a bit harder to write, but it is safe and never segfaults. The idea is to minimize the amount of runtime errors of all sorts. That's also how other features of statically typed languages work.
>>
>>
>> I certainly agree that catching errors at compile time is preferable by far. Where I disagree is the notion that non-nullable types achieve this. I've argued extensively here that they hide errors, not fix them.
>>
>> Also, by "safe" I presume you mean "memory safe" which means free of memory corruption. Null pointer exceptions are memory safe. A null pointer could be caused by memory corruption, but it cannot *cause* memory corruption.
> 
> // t.d
> void main()
> {
>     int* a;
>     a[20000] = 2;
> }
> 
> [C:\Users\Lionello] dmd -run t.d
> 
> [C:\Users\Lionello]
> 
> This code passes on Vista. Granted, needs a big enough offset and some luck, but indexing null will never be secure in the current flat memory models.
> 
> L.

That is a strong argument. If an object is big enough, modifying it via a null reference may still cause memory corruption. Initializing references to null does not guarantee memory safety.


September 28, 2009
Nick Sabalausky wrote:
> "Jeremie Pelletier" <jeremiep@gmail.com> wrote in message news:h9mmre$1i8j$1@digitalmars.com...
>> Ary Borenszweig wrote:
>>> Object is not-nullable, Object? (or whatever syntax you like) is nullable. So that line is a compile-time error: you can't cast a null to an Object (because Object *can't* be null).
>>>
>> union A {
>> Object foo;
>> Object? bar;
>> }
>>
>> Give me a type system, and I will find backdoors :)
>>
> 
> Unions are nothing more than an alternate syntax for a reinterpret cast. And it's an arguably worse syntax because unlike casts, uses of it are indistinguishable from normal safe code, there's nothing to grep for. As such, unions should never be considered any more safe than cast(x)y. The following is just as dangerous as your example above and doesn't even touch the issue of nullability/non-nulability:
> 
> union A {
> int foo;
> float bar;
> }
> 

Yet it's the only way I know of to do bitwise logic on floating points in D to extract the exponent, sign and mantissa for example.

And yes they are much, much more than a simple reinterpret cast, a simple set of casts will not set the size of the union to its largest member. Unions make for elegant types which can have many valid representations:

union Vec3F {
	struct { float x, y, z; }
	float[3] v;
}

I just can't picture D without unions :)
September 28, 2009
Max Samukha wrote:
> Lionello Lunesu wrote:
> 
>> On 27-9-2009 9:20, Walter Bright wrote:
>>> language_fan wrote:
>>>> The idea behind non-nullable types and other contracts is to catch
>>>> these errors on compile time. Sure, the code is a bit harder to write,
>>>> but it is safe and never segfaults. The idea is to minimize the amount
>>>> of runtime errors of all sorts. That's also how other features of
>>>> statically typed languages work.
>>>
>>> I certainly agree that catching errors at compile time is preferable by
>>> far. Where I disagree is the notion that non-nullable types achieve
>>> this. I've argued extensively here that they hide errors, not fix them.
>>>
>>> Also, by "safe" I presume you mean "memory safe" which means free of
>>> memory corruption. Null pointer exceptions are memory safe. A null
>>> pointer could be caused by memory corruption, but it cannot *cause*
>>> memory corruption.
>> // t.d
>> void main()
>> {
>>     int* a;
>>     a[20000] = 2;
>> }
>>
>> [C:\Users\Lionello] dmd -run t.d
>>
>> [C:\Users\Lionello]
>>
>> This code passes on Vista. Granted, needs a big enough offset and some
>> luck, but indexing null will never be secure in the current flat memory
>> models.
>>
>> L.
> 
> That is a strong argument. If an object is big enough, modifying it via a null reference may still cause memory corruption. Initializing references to null does not guarantee memory safety.

How is that corruption? These pointers were purposely set to 0x00000002, corruption I believe is when memory is modified without the programmer being aware of it. For example if the GC was to free memory that is still reachable, that would cause corruption.

Corruption is near impossible to trace back, this case is trivial.
September 28, 2009
Jeremie Pelletier wrote:

> Nick Sabalausky wrote:
>> union A {
>> int foo;
>> float bar;
>> }
>> 
> 
> Yet it's the only way I know of to do bitwise logic on floating points in D to extract the exponent, sign and mantissa for example.

You could add built-in methods for those operations to the float type:

float bar;

boolean s = bar.sign;
...

Union is very flexible, but unfortunately it's also one of the features that can break the type safety in D.
September 28, 2009
Jari-Matti Mäkelä wrote:
> Jeremie Pelletier wrote:
> 
>> Nick Sabalausky wrote:
>>> union A {
>>> int foo;
>>> float bar;
>>> }
>>>
>> Yet it's the only way I know of to do bitwise logic on floating points
>> in D to extract the exponent, sign and mantissa for example.
> 
> You could add built-in methods for those operations to the float type:
> 
> float bar;
> 
> boolean s = bar.sign;
> ...

That would be so inefficient in some cases, you don't always want to shift the data like bar.sign implies.

> Union is very flexible, but unfortunately it's also one of the features that can break the type safety in D.

That's the best thing about systems languages: to have a core set of rules, and to be able to purposely break them. Even better, you still pass go and still get $200.

I don't want a language that takes me by the hand for a walk in the park. I want a language that keeps me on my toes and punch me in the face every now and then :)
September 28, 2009
Jeremie Pelletier wrote:

> Jari-Matti Mäkelä wrote:
>> Jeremie Pelletier wrote:
>> 
>>> Nick Sabalausky wrote:
>>>> union A {
>>>> int foo;
>>>> float bar;
>>>> }
>>>>
>>> Yet it's the only way I know of to do bitwise logic on floating points in D to extract the exponent, sign and mantissa for example.
>> 
>> You could add built-in methods for those operations to the float type:
>> 
>> float bar;
>> 
>> boolean s = bar.sign;
>> ...
> 
> That would be so inefficient in some cases, you don't always want to shift the data like bar.sign implies.

It depends on the boolean representation. I see no reason why a built-in feature should be slower than some bitwise logic operation in user code. After all, the set of operations the language provides for the user is a subset of all possible operations the language implementation can do.