February 04, 2014
On Tuesday, 4 February 2014 at 22:30:39 UTC, Walter Bright wrote:
> On 2/4/2014 4:23 AM, Michel Fortin wrote:
>> For the rare cases where you actually want both versions to work,
>
> I think you're making a vast assumption that the case is rare.
>
> When I write utility functions, I want them to work on as wide a variety of inputs as possible. Otherwise, they are not very useful.
>
>> you can write them twice  or use a template (except in a virtual context), and in both cases
>> you keep the efficiency of not checking for null when the argument is not nullable.
>
> That's just what I wish to avoid. Consider adding more pointer types - the combinatorics quickly explode. Heck, just have two pointer parameters, and you already have 4 cases.
>
> I wonder how Rust deals with this.
>
>
>> In any case, I have yet to understand why @nullable as a storage class would be
>> any better. How do you solve that problem with a storage class?
>
> Good question. I don't have an answer offhand.

 rust would use a reference, basically a pointer that can come
from any smart ptr type, and does not outlive its owner
February 05, 2014
On Tuesday, 4 February 2014 at 22:30:39 UTC, Walter Bright wrote:
> That's just what I wish to avoid. Consider adding more pointer types - the combinatorics quickly explode. Heck, just have two pointer parameters, and you already have 4 cases.
>
> I wonder how Rust deals with this.

Rust does not have null pointers.

In cases where you want to mark an object of some type as having "no value", or being "null", you use a stdlib type Option<T>, which is basically a tagged union plus some static compiler guarantees:

enum Option<T> {
    Some(T),
    None
}

An Option<T> either contains a T (tagged 'Some' then) or nothing (tagged 'None').

If you have a function that takes an Option<T> you can also pass it a (pure, non-nullable) T by specifying Some(myT) as the parameter.
February 05, 2014
Regarding different pointer types in Rust as function arguments:

A function that takes a borrowed pointer &T can also be called with an owning pointer ~T, an RC pointer Rc<T>, or a GC pointer Gc<T>. They all convert neatly to a &T. One function to rule them ... err .. accomodate all.
February 05, 2014
On 2014-02-02 17:30:27 +0000, Namespace said:

> Sounds good. But why @nullable instead of C# choice of "Type?" ?

@nullable is not supposed to do the same thing as "Type?" (or rather the syntatic sugar for Nullabe<Type> template).   Nullable<type> is to enable Value types to be null. For example: Nullable<Double>

@nullable in D is supposed to allow reference types to contain null.  In C# reference types are ALWAYS allowed to be null.

-S

February 05, 2014
On Wednesday, 5 February 2014 at 00:12:11 UTC, Shammah Chancellor wrote:
> On 2014-02-02 17:30:27 +0000, Namespace said:
>
>> Sounds good. But why @nullable instead of C# choice of "Type?" ?
>
> @nullable is not supposed to do the same thing as "Type?" (or rather the syntatic sugar for Nullabe<Type> template).   Nullable<type> is to enable Value types to be null. For example: Nullable<Double>
>
> @nullable in D is supposed to allow reference types to contain null.  In C# reference types are ALWAYS allowed to be null.
>
> -S

class Foo { }

Foo? f;

It's the same.
February 05, 2014
On 2/4/2014 2:39 PM, Dicebot wrote:
> Also non-nullable types should be implicitly cast to nullable parameters so you
> don't always need to support all cases distinctively.

The difficulty comes when needing to transfer the nullability of the argument to the nullability of the return type. Implicit conversions don't help with that.

See inout.
February 05, 2014
On 2/4/2014 3:03 PM, Adam D. Ruppe wrote:
> So bottom line, you don't duplicate functions for the different types. You
> borrow references for processing (analogous to implementing algorithms with
> ranges) and own references for storing... which you need to know about, so only
> one type makes sense.

What happens with this:

    T identity(T t) { return t; }

?
February 05, 2014
On 2/4/2014 4:07 PM, Frank Bauer wrote:
> Regarding different pointer types in Rust as function arguments:
>
> A function that takes a borrowed pointer &T can also be called with an owning
> pointer ~T, an RC pointer Rc<T>, or a GC pointer Gc<T>. They all convert neatly
> to a &T. One function to rule them ... err .. accomodate all.

Again, what happens with:

    T identity(T t) { return t; }

? I.e. the transference of the argument pointer type to the return type?
February 05, 2014
On Tuesday, 4 February 2014 at 21:02:37 UTC, deadalnix wrote:
> Core can share a cache line in read mode, but can't in write mode. That mean that updating the reference count will cause contention on the cache line (core will have to fight for the cache line ownership). That is why immutability + GC is so efficient in a highly concurrent system, and ref counting would ruin that.

Just curious, maybe I got it a bit wrong in my previous reply. It is indeed possible to set the memory type on some CPUs such that you don't get a penalty using some special MTRR (memory type range registers). If the memory type is write-back (regular memory) you get a 43 cycle latency if the cache line might be in multiple local caches and is not dirty (read), 60+ cycle latency if it is dirty (write), and 20-30 cycles latency on local miss, but L3 hit. (if I got that right) But does D actually make sure that immutable types sit in non-write-back memory marked by MTRR?
February 05, 2014
On 2014-02-04 22:30:40 +0000, Walter Bright <newshound2@digitalmars.com> said:

> On 2/4/2014 4:23 AM, Michel Fortin wrote:
>> For the rare cases where you actually want both versions to work,
> 
> I think you're making a vast assumption that the case is rare.
> 
> When I write utility functions, I want them to work on as wide a variety of inputs as possible. Otherwise, they are not very useful.

Well, if you think it's needed I won't contradict you. But that does not bode well for the storage class solution. If you really think it's needed, then you could just double the '?' to give it a similar meaning to inout:

	Object?? passthrough(Object?? o)
	{
		// do something here
		return o;
	}

It looks elegant to me, even if I'm not convinced it is necessary.


>> you can write them twice  or use a template (except in a virtual context), and in both cases you keep the efficiency of not checking for null when the argument is not nullable.
> 
> That's just what I wish to avoid. Consider adding more pointer types - the combinatorics quickly explode. Heck, just have two pointer parameters, and you already have 4 cases.

So you are already worried we'll have to add more pointer types? ;-)

Ok, let's have some fun: '#' means unique now. So we can have four kinds of pointers:

	Object   o1; // not-nullable & not-unique
	Object?  o2; // nullable & not-unique
	Object#  o3; // not-nullable & unique
	Object?# o4; // nullable & unique

And like above, double the marker to make it work like inout:

	Object??## passthrough(Object??## o)
	{
		// have some fun here
		return o;
	}

If you really think more pointer types will be added, then I suggest the implementation for this in the compiler be generic enough to support yes/no/maybe states for a couple of flags. Perhaps even user-defined flags for use by libraries (i.e. Dicebot's SQLEscapedString, or UnicodeNormalizedNFD, or why not PrimeNumber).

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca