December 03, 2019
On Tuesday, 3 December 2019 at 10:02:47 UTC, Andrea Fontana wrote:
> On Tuesday, 3 December 2019 at 09:48:39 UTC, Basile B. wrote:
>> You see what surprises me here is that we cannot express the special type that is `TypeNull` and that can only have one value (`null`) so instead we have to use `auto` or `typeof(null)`.
>
> You can still create an alias anyway :)
>
> alias TypeNull = typeof(null);

Speaking of nice stuff and aliases, suppose you want to
return a nice tuple with named elements?

Option 1: auto

  auto option1() {
      return tuple!(int, "apples", int, "oranges")(1, 2);
  }

Option 2: redundancy

  Tuple!(int, "apples", int, "oranges") option2() {
      return tuple!(int, "apples", int, "oranges")(1, 2);
  }

Option 3: an alias

  alias BadMath = Tuple!(int, "apples", int, "oranges");

  BadMath option3() {
      return BadMath(1, 2);
  }

It wasn't obvious to me that BadMath(...) would work.
It *should* be obvious since this also works:

  ...
      return Tuple!(int, "apples", int, "oranges")(1, 2);

But the convenience of tuple() helped to  mask that.

I was going with silly stuff like

  ...
      return cast(BadMath) tuple(1, 2);

December 03, 2019
On Tuesday, December 3, 2019 3:03:22 AM MST Basile B. via Digitalmars-d- learn wrote:
> On Tuesday, 3 December 2019 at 09:58:36 UTC, Jonathan M Davis
>
> wrote:
> > On Tuesday, December 3, 2019 12:12:18 AM MST Basile B. via
> >
> > Digitalmars-d- learn wrote:
> >> I wish something like this was possible, until I change the return type of `alwaysReturnNull` from `void*` to `auto`.
> >>
> >>
> >> ---
> >> class A {}
> >> class B {}
> >>
> >> auto alwaysReturnNull() // void*, don't compile
> >> {
> >>
> >>      writeln();
> >>      return null;
> >>
> >> }
> >>
> >> A testA()
> >> {
> >>
> >>      return alwaysReturnNull();
> >>
> >> }
> >>
> >> B testB()
> >> {
> >>
> >>      return alwaysReturnNull();
> >>
> >> }
> >>
> >> void main()
> >> {
> >>
> >>      assert( testA() is null );
> >>      assert( testB() is null );
> >>
> >> }
> >> ---
> >>
> >> OMG, isn't it nice that this works ?
> >>
> >> I think that this illustrates an non intuitive behavior of auto
> >> return types.
> >> One would rather expect auto to work depending on the inner
> >> return type.
> >
> > The void* version doesn't work, because void* doesn't implicitly convert to a class type. It has nothing to do with null. auto works thanks to the fact that typeof(null) was added to the language a while back, and since class references can be null, typeof(null) implicitly converts to the class type. Before typeof(null) was added to the language, null by itself had no type, since it's just a literal representing the null value for any pointer or class reference. The result was that using null in generic code or with auto could run into issues. typeof(null) was added to solve those problems.
> >
> > - Jonathan M Davis
>
> That's interesting details of D developement. Since you reply to the first message I think you have not followed but in the last reply I told that maybe we should be able to name the type of null. I think this relates to TBottom too a bit.

There isn't much point in giving the type of null an explicit name given that it doesn't come up very often, and typeof(null) is quite explicit about what the type is. Also, anyone doing much generic programming in D is going to be well versed in typeof. They might not know about typeof(null) explicitly, but they should recognize what it means when they see it, and if someone were trying to get the type of null, it would be the obvious thing to try anyway. And typeof(null) isn't even the prime case where typeof gets used on something other than an object. From what I've seen, typeof(return) gets used far more.

As for TBottom, while the DIP does give it a relationship to null, they're still separate things, and giving typeof(null) a name wouldn't affect TBottom at all.

- Jonathan M Davis



December 03, 2019
On Tuesday, 3 December 2019 at 10:19:02 UTC, Jonathan M Davis wrote:
> On Tuesday, December 3, 2019 3:03:22 AM MST Basile B. via Digitalmars-d- learn wrote:
>> [...]
>
> There isn't much point in giving the type of null an explicit name given that it doesn't come up very often, and typeof(null) is quite explicit about what the type is. Also, anyone doing much generic programming in D is going to be well versed in typeof. They might not know about typeof(null) explicitly, but they should recognize what it means when they see it, and if someone were trying to get the type of null, it would be the obvious thing to try anyway. And typeof(null) isn't even the prime case where typeof gets used on something other than an object. From what I've seen, typeof(return) gets used far more.
>
> [...]

you're right but I see two cases:

- transpiling
- header generation
December 03, 2019
On Tuesday, December 3, 2019 3:23:20 AM MST Basile B. via Digitalmars-d- learn wrote:
> On Tuesday, 3 December 2019 at 10:19:02 UTC, Jonathan M Davis
>
> wrote:
> > On Tuesday, December 3, 2019 3:03:22 AM MST Basile B. via
> >
> > Digitalmars-d- learn wrote:
> >> [...]
> >
> > There isn't much point in giving the type of null an explicit name given that it doesn't come up very often, and typeof(null) is quite explicit about what the type is. Also, anyone doing much generic programming in D is going to be well versed in typeof. They might not know about typeof(null) explicitly, but they should recognize what it means when they see it, and if someone were trying to get the type of null, it would be the obvious thing to try anyway. And typeof(null) isn't even the prime case where typeof gets used on something other than an object. From what I've seen, typeof(return) gets used far more.
> >
> > [...]
>
> you're right but I see two cases:
>
> - transpiling
> - header generation

I don't see why either of those would be a problem. For a transpiler, typeof(null) and an explicit type name for typeof(null) would be the same thing, and it would have to be translated to something that would work in the other language either way. As for header generation, do you mean .di files? They'd just use typeof(null) explicitly, whereas if you're talking about something like having extern(C) functions in D and declaring a corresponding .h file, typeof(null) wouldn't work anyway, because there is no equivalent in C. In either case, whether you represent the type as typeof(null) or by an explicit name in the D source code is irrelevant. It would mean the same thing regardless. Having an explicit name wouldn't really be any different from declaring an alias like

alias TypeOfNull = typeof(null);

The type is the same either way and would be treated the same by the compiler or by any tool that needed to translate it to another language. It's what the type is that matters, not how its represented in the D source code. The only real difference would be what the programmer would see when interacting with the D source code. It would be like arguing over whether the root class object should be called Object or Root. It would be the same thing either way, just with a different name.

- Jonathan M Davis



December 03, 2019
On Tue, Dec 03, 2019 at 03:19:02AM -0700, Jonathan M Davis via Digitalmars-d-learn wrote:
> On Tuesday, December 3, 2019 3:03:22 AM MST Basile B. via Digitalmars-d- learn wrote:
[...]
> > [...] maybe we should be able to name the type of null. I think this relates to TBottom too a bit.
> 
> There isn't much point in giving the type of null an explicit name given that it doesn't come up very often, and typeof(null) is quite explicit about what the type is.

Just add this line somewhere in object.d and we're good to go:

	alias Null = typeof(null);

:-)


[...]
> As for TBottom, while the DIP does give it a relationship to null, they're still separate things, and giving typeof(null) a name wouldn't affect TBottom at all.
[...]

We need to tread carefully here, because of the unfortunate conflation of top and bottom types we inherited from C in the form of the keyword `void`, which greatly confuses the issue.

The thing is, `void` means "no return type" (or "no type" in some contexts), i.e., void == TBottom in that case.  However, `void*` does NOT mean a pointer to TBottom; rather, it's a *top type* that includes pointers of every kind (this can be seen in the fact that any pointer implicitly converts to void*).

I.e., the relationship between `void` and `void*` is NOT the same as the relationship with `T` and `T*` for any other T.

This unfortunate overloading of `void` to mean both top and bottom types in different contexts misleads many C (and D) programmers into the wrong understanding of what a bottom type is (or what a top type is), and how it should behave.


T

-- 
The problem with the world is that everybody else is stupid.
December 03, 2019
On Tuesday, 3 December 2019 at 17:45:27 UTC, H. S. Teoh wrote:
> The thing is, `void` means "no return type" (or "no type" in some contexts), i.e., void == TBottom in that case.

This is incorrect. `void` as a return type is a unit type; that is, a type with exactly one value. A function with a return type of TBottom is one that never returns at all--for example, libc's `exit` or POSIX's `execve`.
December 03, 2019
On Tue, Dec 03, 2019 at 09:08:55PM +0000, Paul Backus via Digitalmars-d-learn wrote:
> On Tuesday, 3 December 2019 at 17:45:27 UTC, H. S. Teoh wrote:
> > The thing is, `void` means "no return type" (or "no type" in some contexts), i.e., void == TBottom in that case.
> 
> This is incorrect. `void` as a return type is a unit type; that is, a type with exactly one value. A function with a return type of TBottom is one that never returns at all--for example, libc's `exit` or POSIX's `execve`.

Ah, my bad.  See?  This whole `void` business just throws me off. No wonder we can never get things straight when it comes to top/bottom types in C/C++/D.


T

-- 
He who sacrifices functionality for ease of use, loses both and deserves neither. -- Slashdotter
December 03, 2019
On Tuesday, 3 December 2019 at 17:45:27 UTC, H. S. Teoh wrote:
> The thing is, `void` means "no return type" (or "no type" in some contexts), i.e., void == TBottom in that case.

Not *quite* correct. void is not a bottom type; it's a unit type, meaning that it's a type with only 1 value (as is null, interestingly). void does not mean "no return type"; it means "there's only 1 possible value that can be returned". A function returning TBottom means that the function will never return, e.g., it loops forever, or throws an exception, etc.

I agree with the OP that it's silly not to give typeof(null) a name. As null is a unit type, we could easily have `null` stand in for typeof(null) as well. A type that contains only one value can be synonymous with that value (see also, Rust's unit type (), which has one value, ()).


December 03, 2019
On Tuesday, 3 December 2019 at 22:11:39 UTC, Meta wrote:
> On Tuesday, 3 December 2019 at 17:45:27 UTC, H. S. Teoh wrote:
>> The thing is, `void` means "no return type" (or "no type" in some contexts), i.e., void == TBottom in that case.
>
> Not *quite* correct. void is not a bottom type; it's a unit type, meaning that it's a type with only 1 value (as is null, interestingly). void does not mean "no return type"; it means "there's only 1 possible value that can be returned". A function returning TBottom means that the function will never return, e.g., it loops forever, or throws an exception, etc.

Whoops, skimmed over the post already mentioning this.
December 03, 2019
On Tuesday, 3 December 2019 at 10:13:30 UTC, mipri wrote:
> Speaking of nice stuff and aliases, suppose you want to
> return a nice tuple with named elements?
>
> Option 1: auto
>
>   auto option1() {
>       return tuple!(int, "apples", int, "oranges")(1, 2);
>   }
>
> Option 2: redundancy
>
>   Tuple!(int, "apples", int, "oranges") option2() {
>       return tuple!(int, "apples", int, "oranges")(1, 2);
>   }
>
> Option 3: an alias
>
>   alias BadMath = Tuple!(int, "apples", int, "oranges");
>
>   BadMath option3() {
>       return BadMath(1, 2);
>   }

Option 4: typeof(return)

  Tuple!(int, "apples", int, "oranges") option4() {
      return typeof(return)(1, 2);
  }