Re: Query for -dip1000

2019-02-11 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, February 11, 2019 3:23:25 AM MST Seb via Digitalmars-d-learn 
wrote:
> On Monday, 11 February 2019 at 09:29:13 UTC, Jonathan M Davis
>
> wrote:
> > On Sunday, February 10, 2019 1:04:29 PM MST Per Nordlöw via
> >
> > Digitalmars-d- learn wrote:
> >> [...]
> >
> > A quick grep of Phobos shows a version(DIP1000) block in
> > std/typecons.d, which appears to be used to make it so that a
> > particular unittest block is only compiled in when -dip1000 is
> > used,  so it looks like there's a version identifier for it.
> >
> > - Jonathan M Davis
>
> That one has been added manually:
>
> https://github.com/dlang/phobos/blob/master/dip1000.mak
>
> The detection would have been better...

Honestly, having an explicit version is far better than trying to detect it
in an ad-hoc manner. It's actually guaranteed to be right in that case,
whereas ad-hoc tests are more likely to have problems - especially if
they're around for a while, and things change that weren't anticipated when
the code was written. So, I'd actually argue that manually setting it as
part of the build was a better idea than trying to detect it, but if it's
manually set as part of the build instead of being built into the compiler,
then it doesn't help anyone else. Though honestly, it seems to me that
having version identifiers for transitional compiler flags like that is
probably a good idea, since it makes transitioning code easier. The best
that we can do otherwise is generally using __VERSION__, and that only works
once the change is the default.

- Jonathan M Davis






Re: Query for -dip1000

2019-02-11 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, February 10, 2019 1:04:29 PM MST Per Nordlöw via Digitalmars-d-
learn wrote:
> Is there a way to query if the -dip1000 flag has been passed to
> the compiler? I need it for enabling certain DIP-1000 escape
> analysis tests only when -dip1000 has been passed.
>
> For instance
>
>  static assert(!__traits(compiles, {
>  char[] f()
>  {
>  char[2] x;
>  return x[].splitterASCII!(_ => _ == '
> ').front;
>  }
>  }));
>
> at
>
> https://github.com/nordlow/phobos-next/blob/bd2fe42978aab2313977042c858d77
> c5766538e8/src/splitter_ex.d#L110
>
> Or do I have to write a trait myself?

A quick grep of Phobos shows a version(DIP1000) block in std/typecons.d,
which appears to be used to make it so that a particular unittest block is
only compiled in when -dip1000 is used,  so it looks like there's a version
identifier for it.

- Jonathan M Davis






Re: dirEntries within static foreach: memory.d(827): Error: fakePureErrno cannot be interpreted at compile time, because it has no available source code

2019-02-10 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, February 10, 2019 5:19:02 PM MST kdevel via Digitalmars-d-learn 
wrote:
> I am trying to get this code compiled:
>
> ```TemplateStore.d
> module TemplateStore;
> import std.path;
> import std.conv;
> import std.file;
>
> immutable string[string] template_map;
>
> static this ()
> {
> static foreach (f; dirEntries (``, `*.html`,
> SpanMode.shallow)) {
>pragma (msg, `reading template <` ~ f ~ ">");
>template_map[f] = import (f);
> }
> }
> ```
>
> dmd v2.082.0 says
>
> ...linux/bin64/../../src/druntime/import/core/memory.d(827):
> Error: fakePureErrno cannot be interpreted at compile time,
> because it has no available source code
> Error: invalid foreach aggregate 
> Error: invalid foreach aggregate 
>
> If I use an immutable array of file names instead of dirEntries
> the code compiles, but I don't want to update that array each
> time a new template file is added.
>
> As a workaround I wrote a helper which writes the quoted
> filenames comma-separated into a file named `LS` using this
> fragment:
>
> foreach (f; dirEntries (``, `*.html`, SpanMode.shallow))
>writefln ("`%s`,", f);
>
> Then I try to convince the dmd compiler to read LS and use its
> content as initializer for the immutable array template_files:
>
> immutable LS = import (`LS`);
> pragma (msg, `LS = <` ~ LS ~ `>`);
> immutable template_files = [
>mixin(LS)
> ];
>
> dmd now says (1) if the list in LS has a trailing comma:
>
> TemplateStore.d-mixin-13(26): Error: expression expected, not
> End of File
>
> or (2) if the list has no trailing comma:
>
> TemplateStore.d-mixin-13(13): Error: Using the result of a
> comma expression is not allowed
> TemplateStore.d-mixin-13(14): Error: Using the result of a
> comma expression is not allowed
> TemplateStore.d-mixin-13(15): Error: Using the result of a
> comma expression is not allowed
>
>
> What can I do about it?

Nothing. You can't call C functions during CTFE, because the compiler
doesn't have their source code, and all functions that interact with the
filesystem have to ultimately call C functions. So, you can't use something
like dirEntries with CTFE.

The only way that you can do anything along the lines of reading files
during CTFE is to use string imports to insert the text of a file directly
into the module.

- Jonathan M Davis





Re: Should D file end with newline?

2019-02-10 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, February 10, 2019 2:06:50 AM MST Cym13 via Digitalmars-d-learn 
wrote:
> On Sunday, 10 February 2019 at 02:12:43 UTC, Jonathan M Davis
>
> wrote:
> > On Saturday, February 9, 2019 2:19:27 PM MST Victor Porton via
> >
> > Digitalmars- d-learn wrote:
> >> ISO C++ specifies that the C++ file must end with a newline.
> >>
> >> Should D file end with newline, too?
> >
> > No, there is no need to end D files with a newline. I would
> > guess that the vast majority of D files end with a closing
> > brace. I just looked at a bunch of files in the standard
> > library for the heck of it, and almost all of the ones I looked
> > at ended with a closing brace. And those that didn't ended with
> > something like an enum declaration and not a newline.
> > Personally, I don't leave newlines at the end of files, because
> > it looks messy. I don't even recall doing that in C++, though I
> > do recall that there supposedly be a rule about it. It seems
> > like a pretty bizarre requirement to me, but regardless, I'm
> > quite sure that D does not have that requirement.
> >
> > - Jonathan M Davis
>
> If you used a text editor or IDE to write that final closing
> brace then I'm pretty confident it does add the newline character
> at the end. That won't result in an empty line on display. Try
> using an hex editor to check if you're curious.

I use (g)vim, which I would expect to show anything like trailing newlines.
It usually shows everything, including rendering control characters and the
like in a way that you know exactly what's there. Opening up
std/algorithm/mutation.d in vim as an example, it clearly ends in a closing
brace with no trailing newline. However if I feed it into hexdump

...
00158f0 2020 6373 706f 2865 7865 7469 2029 7266
0015900 6565 7328 702e 7274 3b29 7d0a 000a
001590d

hexdump shows a newline followed by a null character followed by a newline
after the carriage return. So, it does indeed look like extra junk is there
after the data in the file, and surprisingly, vim doesn't showing it (or
anything indicating that it's there). I don't know why any of that would be
there, since it seems pointless me, but it is there in
std/algorithm/mutation.d. On the other hand, if I open up
std/datetime/systime.d with hexdump, it shows

007f8b0 0a7d 2020 2020 2020 2020 0a7d 2020 2020
007f8c0 0a7d 0a7d
007f8c4

so it actually ends on a closing braces. So, maybe some text editors shove
extra junk on the end and others don't? I don't know. Either way, I find it
very odd that vim doesn't show anything after the closing brace when it's
there. Both of those files show a closing brace as their last character when
opened in vim. Looking quickly at some of my personal projects, I don't see
any files which end with anything other than a closing brace according to
either vim or hexdump. And since all of those were created with (g)vim, I'd
say that vim does not put those extra characters on the end (though it will
allow them and otherwise ignore them). That also makes it clear that no
newline or any other special sequence of characters is required at the end
of a .d file, because all of those files work just fine with their last
character being a closing brace.

Curiously, if I create a .cpp or .c file with vim and have it end with a
curly brace, vim _does_ append a newline followed by a null character
followed by a newline at the end of the file. So, I guess that vim looks at
the extension and realizes that C/C++ has such a requirement and takes care
of it for you, but it does not think that .d files need them and adds
nothing extra for them. It doesn't add anything for a .txt file when I tried
it either.

In any case, if your text editor happens to insert those extra characters at
the end of a .d file, then they may end up there, but given what hexdump
says and what dmd accepts, I can verify that they aren't actually required
for .d files.

- Jonathan M Davis





Re: Should D file end with newline?

2019-02-09 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, February 9, 2019 2:19:27 PM MST Victor Porton via Digitalmars-
d-learn wrote:
> ISO C++ specifies that the C++ file must end with a newline.
>
> Should D file end with newline, too?

No, there is no need to end D files with a newline. I would guess that the
vast majority of D files end with a closing brace. I just looked at a bunch
of files in the standard library for the heck of it, and almost all of the
ones I looked at ended with a closing brace. And those that didn't ended
with something like an enum declaration and not a newline. Personally, I
don't leave newlines at the end of files, because it looks messy. I don't
even recall doing that in C++, though I do recall that there supposedly be a
rule about it. It seems like a pretty bizarre requirement to me, but
regardless, I'm quite sure that D does not have that requirement.

- Jonathan M Davis





Re: Is it possible to modify shared struct array in a function.

2019-02-08 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, February 8, 2019 4:27:44 AM MST Eduard Staniloiu via Digitalmars-
d-learn wrote:
> On Friday, 8 February 2019 at 06:55:15 UTC, Jerry wrote:
> > On Friday, 8 February 2019 at 04:51:08 UTC, Sudhi wrote:
> >> On Friday, 8 February 2019 at 04:30:23 UTC, Arun
> >>
> >> Chandrasekaran wrote:
> >>> On Friday, 8 February 2019 at 04:13:39 UTC, Sudhi wrote:
>  [...]
> >>>
> >>> Works fine for me with DMD64 D Compiler v2.083.1.
> >>> https://run.dlang.io/is/RRM8GU
> >>
> >> My example code was wrong. Below is the right one.
> >>
> >> struct Company
> >> {
> >>
> >> string name;
> >> string location;
> >>
> >> }
> >>
> >> struct Racks
> >> {
> >>
> >> int number;
> >> int location;
> >>
> >> }
> >>
> >> struct Metadata
> >> {
> >>
> >> string name;
> >> Company[] companies;
> >> Racks[] racks;
> >>
> >> }
> >>
> >> struct Item
> >> {
> >>
> >> Metadata[] met;
> >> int count;
> >>
> >> }
> >>
> >> shared (Item) item;
> >>
> >> void main()
> >> {
> >>
> >>updateMetadata();
> >>
> >> }
> >>
> >> void updateMetadata()
> >> {
> >>
> >>Company company;
> >>company.name = "Hello";
> >>company.location = "Bangalore";
> >>item.met.companies ~= company;
> >>import std.stdio: writeln;
> >>writeln(item);
> >>
> >> }
> >>
> >> https://run.dlang.io/is/iem0PY
> >
> > You have to cast away shared:
> >
> > auto loc_item = cast(Item) item;
> > loc_item.met ~= m;
> > item = cast(shared) loc_item;
> >
> > Just to be clear, this is not threadsafe and require a mutex if
> > you do this other than as init in main.
>
> You do not need to cast away shared. You had a couple of issues
> with your `updateMetadata()` function.
>
> First of, `met` is an array, so you need to index it: your code
> `item.met.companies ~= company` becomes `item.met[0].companies ~=
> company`. This will compile, but throw a range error because you
> don't have any `Metadata` object in your `met` array.
>
> I have typed below the revised form of your function
>
> ```
> void updateMetadata()
> {
> // create a Company instance. This must be shared
> shared Company company;
> company.name = "Hello";
> company.location = "Bangalore";
>
> // create a shared Metadata instance
> shared Metadata m;
> m.name = "m";
>
> // append m to the array of meta
> item.met ~= m;
> // append the company to the array of companies, for a given
> meta
> item.met[0].companies ~= company;
>
> import std.stdio: writeln;
> writeln(item);
> }
> ```
>
> The working version is at https://run.dlang.io/is/RvRKrU
>
> Cheers,
> Edi

Honestly, the fact that that code compiles is a bug. You're not supposed to
be able to modify shared objects in a manner which isn't guaranteed to be
atomic, because it's not thread-safe. The compiler catches it in a number of
places, but there are many where it currently doesn't.

But regardless of whether the compiler allows such mutation, a mutex (or
similar protection mechanism) needs to be used in order to make the code
thread-safe.

- Jonathan M Davis





Re: Singleton in Action?

2019-02-03 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, February 3, 2019 2:41:48 AM MST Ron Tarrant via Digitalmars-d-
learn wrote:
> On Saturday, 2 February 2019 at 19:40:25 UTC, Andre Pany wrote:
> > https://rosettacode.org/wiki/Singleton#D
>
> Do you know if this is for a current version of D? The compiler
> is choking on the import statements, complaining that it can't
> read std/thread.d and std/c/time.d

I don't recall std.thread ever existing, and std.c.time hasn't been around
for a while. Thread is in core.thread, and all of the C bindings for
standard C and OS APIs are supposed to be in druntime. So, the equivalent to
C's time.h would be core.stdc.time.

- Jonathan M Davis





Re: Implement Interface Using Super

2019-01-29 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, January 28, 2019 10:41:55 PM MST Meta via Digitalmars-d-learn 
wrote:
> On Monday, 28 January 2019 at 22:17:56 UTC, Steven Schveighoffer
>
> wrote:
> > On 1/28/19 3:28 PM, Jonathan Levi wrote:
> >> On Sunday, 27 January 2019 at 09:31:46 UTC, bauss wrote:
> >>> On Sunday, 27 January 2019 at 05:37:57 UTC, Jonathan Levi
> >>>
> >>> wrote:
>  This works in LDC *but not* DMD?
>  . . .
>  Is this a bug in DMD *or* in LDC?
> >>>
> >>> There is no bug here.
> >>
> >> So... LDC is the one that is bugged?
> >
> > Yeah, that's odd. It should be the same result, as they both
> > have the same semantics for the front end.
> >
> > I'll defer to an LDC developer to answer that, but in truth, it
> > really should be the way LDC implements it, even if that's not
> > how the language spec is.
> >
> >> I think it would have been nice to have a way of explicitly
> >> use the super method to implement an interface without having
> >> to rewrite the whole signature.  I thought I remember seeing a
> >> way once, but I must have been dreaming.
> >
> > I agree.
> >
> > BTW, the typeof(super) requirement is super-annoying. alias x =
> > super.x; is clear, I don't see why we need to specify
> > typeof(super) in this context at least.
> >
> > -Steev
>
> It's because aliases do not support context pointers, I'm pretty
> sure.

Yeah. It would be like trying to do something like

alias x = this.x;

As it stands, I believe that super is always either used as a function call
to the constructor or to mean the this pointer for the base class. I don't
think that it ever means the type of the base class - just like this never
means the type of the current class or struct. And their usage is pretty
much identical. They're both either used for calling a constructor or for
accessing the pointer/reference of the object. It's just that one of them is
for the current class or struct, whereas the other is for a base class of
the current class. The only difference in syntax that I can think of between
them at the moment is that this is also used to name constructors when
they're declared, whereas super is not used in that sort of way (since any
constructor that would be referenced by super would be declared with this,
not super).

- Jonathan M Davis





Re: opEquals() non-standard return type

2019-01-23 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, January 23, 2019 8:19:06 AM MST Jacob Shtokolov via 
Digitalmars-d-learn wrote:
> Hi,
>
> I'm trying to check whether it's possible to implement Python's
> SQLAlchemy-like query syntax in D, but I get stuck a bit.
>
> Here is a simple example of what I want to achieve:
>
> ```
> auto result = User.filter(User.id == 10);
> result = User.filter(User.name == "John");
> result = User.filter(User.age > 18);
> ```
>
> Expressions like `User.id == 10`, `User.age > 18`, etc. should
> return a struct instead of a bool (let's call it `struct
> BinaryExpression`).
>
> So I'm making the two versions of opEquals: one returns a
> BinaryExpression, and the second - a boolean value.
>
> However, when I want to use the same expression for the `if`
> operator, the compiler cannot decide what function to call and
> shows an error: "overloads bool(int b) and BinaryExpr!int(int b)
> both match argument list for opEquals".
>
>
> I'm wondering, is that possible to declare multiple versions of
> opEquals() and evaluate them in the different places depending on
> return type?
>
> Here is my test code to check: https://run.dlang.io/is/yTFHWp
> Gist:
> https://gist.github.com/run-dlang/67ec42ca73d56d310e8ae765fabede69
>
> Thanks!

D's operator overloading is specifically designed around the idea that
overloaded operators are supposed to act like the operators on the built-in
types and that they _not_ be used for building syntax. opEquals is supposed
to only return bool. If you attempt to make it return pretty much anything
else, you're begging for trouble.

But regardless of the specifics of operator overloading in D, D does not
support overloading _any_ functions on the return type. Overloading is only
done based an a function's arguments. You've declared two overloads with the
exact same types for all of their parameters such that they only differ by
their return type, and you can't do that in D.

- Jonathan M Davis





Re: How to ensure string compatibility In D?

2019-01-23 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, January 23, 2019 5:42:55 AM MST FrankLike via Digitalmars-d-
learn wrote:
> On Wednesday, 23 January 2019 at 10:44:51 UTC, Jonathan M Davis
>
> wrote:
> > On Tuesday, January 22, 2019 2:49:00 PM MST bauss via
> > Digitalmars-d-learn wrote:
> >
> > toUTFz is the generic solution. toStringz exists specifically
>
> Error: template std.utf.toUTFz cannot deduce function from
>   argument types !()(string), candidates are:
> E:\D\DMD2\WINDOWS\BIN\..\..\src\phobos\std\utf.d(3070):
> std.utf.toUTFz(P)

As the documentation shows, toUTFz requires a target type just like
std.conv.to does. toUTF16z is a convenience wrapper around toUTFz which
specifies the target type as const(wchar)*.

> I have solved the problem in this way:
>
> import core.sys.windows.windows;
> import std.stdio;
> import std.string;
> import std.conv;
>
> void main()
> {
>   autostrA_Z ="CD"w;
>   auto type = GetDriveType(tos(to!wstring(strA_Z[0])~":\\"));
>   writeln(to!wstring(strA_Z[0])~" is ",type);
> }
>
> private auto tos(T)(T str)
> {
>   version (ANSI)
>   {
>   writeln("ANSI");
>   return cast(const(char)*)(str);
>   }
>   else
>   {
>   writeln("Unicode");
>   return cast(const(wchar)*)(str);
>
>   }
> }
>
> Thanks.

std.conv.to will allow you to convert between string and wstring, but for
calling C functions, you still need the strings to be zero-terminated unless
the function specifically takes an argument indicating the number of
characters in the string. Strings in D are not zero-terminated, so
std.conv.to is not going to produce strings that work with C functions.
std.conv.to and std.utf.toUTFz solve different problems.

Also, strings of char in D are UTF-8, _not_ ANSI, so passing them to any of
the A functions from Windows is not going to work correctly. If you want to
do that, you need to use toMBSz and fromMBSz from std.windows.charset. But
really, there's no reason at this point to ever use the A functions. There
are frequently issues with them that the W functions don't have, and the W
functions actually support Unicode. The only real reason to use the A
functions would be to use an OS like Windows 98 which didn't have the W
functions, and D doesn't support such OSes. So, I would strongly discourage
you from doing anything with the A functions, let alone trying to write your
code so that it uses either the A or W functions depending on some argument.
That's an old Windows-ism that I wouldn't even advise using in C/C++ at this
point. It's just begging for bugs. And since D doesn't have the macros for
all of the various Windows functions for swapping between the A and W
versions of the functions like C/C++ does, you have to explicitly call one
or the other in D anyway, making it really hard to call the wrong one
(unlike in C/C++, where screwing up how your project is compiled can result
in accidentally using the A functions instead of the W functions). This
really sounds like you're trying to duplicate something from C/C++ that
doesn't make sense in D and really shouldn't be duplicated in D.

- Jonathan M Davis






Re: How to ensure string compatibility In D?

2019-01-23 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, January 22, 2019 2:49:00 PM MST bauss via Digitalmars-d-learn 
wrote:
> On Tuesday, 22 January 2019 at 19:14:43 UTC, Jonathan M Davis
>
> wrote:
> > On Tuesday, January 22, 2019 12:05:32 PM MST Stefan Koch via
> >
> > Digitalmars-d- learn wrote:
> >> On Tuesday, 22 January 2019 at 16:47:45 UTC, FrankLike wrote:
> >> > On Tuesday, 22 January 2019 at 16:18:17 UTC, Adam D. Ruppe
> >> >
> >> > wrote:
> >> >> Use "mystring"w, notice the w after the closing quote.
> >> >
> >> > Or toStringz is not work like c_str() in C++?
> >>
> >> stringz creates a char*
> >> but you need a wchar*
> >
> > std.utf.toUTF16z or toUTFz can do that for you, though if your
> > string is already a wstring, then you can also just concatenate
> > '\0' to it. the big advantage toUTF16z is that it will also
> > convert strings of other character types rather than just
> > wstrings. So, you can write your program using proper UTF-8
> > strings and then only convert to UTF-16 for the Windows stuff
> > when you have to.
> >
> > https://dlang.org/phobos/std_utf.html#toUTF16z
> > https://dlang.org/phobos/std_utf.html#toUTFz
> >
> > - Jonathan M Davis
>
> Is there a reason we cannot implement toStringz like:
>
> immutable(TChar)* toStringz(TChar = char)(scope const(TChar)[] s)
> @trusted pure nothrow;
> // Couldn't find a way to get the char type of a string, so
> couldn't make the following generic:
> immutable(char)* toStringz(return scope string s) @trusted pure
> nothrow;
> immutable(wchar)* toStringz(return scope wstring s) @trusted pure
> nothrow;
> immutable(dchar)* toStringz(return scope dstring s) @trusted pure
> nothrow;

toUTFz is the generic solution. toStringz exists specifically for UTF-8
strings, and it exists primarily because it attempts to avoid actually
appending or allocating to the string by checking to see if there's a null
character after the end of the string (which is done, because that's always
the case with string literals). If you don't care about it trying to avoid
that allocation, then there arguably isn't much point to toStringz, and you
might as well just to (str ~ '\0').ptr

- Jonathan M Davis





Re: How to ensure string compatibility In D?

2019-01-22 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, January 22, 2019 12:05:32 PM MST Stefan Koch via Digitalmars-d-
learn wrote:
> On Tuesday, 22 January 2019 at 16:47:45 UTC, FrankLike wrote:
> > On Tuesday, 22 January 2019 at 16:18:17 UTC, Adam D. Ruppe
> >
> > wrote:
> >> Use "mystring"w, notice the w after the closing quote.
> >
> > Or toStringz is not work like c_str() in C++?
>
> stringz creates a char*
> but you need a wchar*

std.utf.toUTF16z or toUTFz can do that for you, though if your string is
already a wstring, then you can also just concatenate '\0' to it. the big
advantage toUTF16z is that it will also convert strings of other character
types rather than just wstrings. So, you can write your program using proper
UTF-8 strings and then only convert to UTF-16 for the Windows stuff when you
have to.

https://dlang.org/phobos/std_utf.html#toUTF16z
https://dlang.org/phobos/std_utf.html#toUTFz

- Jonathan M Davis





Re: Compiling to 68K processor (Maybe GDC?)

2019-01-21 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, January 21, 2019 10:08:23 AM MST Johan Engelen via Digitalmars-d-
learn wrote:
> On Saturday, 19 January 2019 at 17:45:41 UTC, Patrick Schluter
>
> wrote:
> > Afaict NULL pointer derefernecing must fault for D to be
> > "usable". At least all code is written with that assumption.
>
> Dereferencing `null` in D is implementation defined
> (https://dlang.org/spec/arrays.html#pointers).
>
> For LDC, dereferencing `null` invokes Undefined Behavior [1].
> However, the compiler does try to be a little friendly towards
> the programmer. UB includes just ignoring the dereference, but if
> you are blatantly dereferencing `null` with optimization enabled,
> the compiler generates a `ud2` instruction for you:
> https://d.godbolt.org/z/5VLjFt
>
> -Johan
>
> [1] Now I am not quite sure yet whether Undefined Behavior is
> part of the set of behaviors allowed to choose from for
> Implementation Defined behavior. ;-)

It is my understanding that Walter specifically chose the term
"implementation defined" rather than "undefined," because undefined behior
is not allowed, and that page you linked to supports that in that it lists
"implementation defined" and "undefined" separately when talking about the
behavior of dereferencing pointers. But you would have to discuss it with
Walter to know exactly what he meant. The spec really should define those
terms somewhere, but I doubt that it does. I haven't read through the spec
in much detail recently though, so maybe it's in there somewhere.

- Jonathan M Davis





Re: Compiling to 68K processor (Maybe GDC?)

2019-01-20 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, January 19, 2019 10:45:41 AM MST Patrick Schluter via 
Digitalmars-d-learn wrote:
> On Saturday, 19 January 2019 at 12:54:28 UTC, rikki cattermole
>
> wrote:
> > On 20/01/2019 1:38 AM, Edgar Vivar wrote:
> >> Hi,
> >>
> >> I have a project aiming to old 68K processor. While I don't
> >> think DMD would be able for this on the other hand I think GDC
> >> can, am I right?
> >>
> >> If yes would be any restriction of features to be used? Or the
> >> compiler would be smart enough to handle this properly?
> >>
> >> Edgar V.
> >
> > Potentially.
> >
> > D is designed to only work on 32bit+ architectures. The 68k
> > series did have 32bit versions of them.
> >
> > After a quick check it does look like LDC is out as LLVM has
> > not yet got support for M68k target. Which is unfortunate
> > because with the -betterC flag it could have pretty much out of
> > the box worked. Even if you don't have most of D at your
> > disposal e.g. classes and GC (but hey old cpu! can't expect
> > that).
> >
> > I have no idea about GDC, but the -betterC flag is pretty
> > recent so its support may not be what you would consider first
> > class there yet.
>
> At least 68030 (or 68020+68851) would be necessary for proper
> segfault managing (MMU) and an OS that uses it. Afaict NULL
> pointer derefernecing must fault for D to be "usable". At least
> all code is written with that assumption.

For @safe to work properly, dereferencing null must be @safe, which means
more or less means that either it results in a segfault, or the compiler has
to add additional checks to ensure that null isn't dereferenced. The
situation does get a bit more complicated in the details (e.g. calling a
non-virtual member function on a null pointer or reference wouldn't segfault
if the object's members are never actually accessed, and that's fine,
because it doesn't violate @safe), but in general, either a segfault must
occur, or the compiler has to add extra checks so that invalid memory is not
accessed. At this point, AFAIK, all of the D compilers assume that
dereferencing null will segfault, and they don't ever add additional checks.
If an architecture does not segfault when dereferencing null, then it will
need special handling by the compiler, and I don't think that ever happens
right now. So, if D were compiled on such an architecture, @safe wouldn't
provide the full guarantees that it's supposed to.

- Jonathan M Davis





Re: Deprecation: foreach: loop index implicitly converted from size_t to int

2019-01-18 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, January 18, 2019 8:34:22 AM MST Michael via Digitalmars-d-learn 
wrote:
> On Friday, 18 January 2019 at 13:29:29 UTC, Adam D. Ruppe wrote:
> > On Friday, 18 January 2019 at 12:27:17 UTC, Michael wrote:
> >> This, to be, looks like quite the explicit conversion, no?
> >
> > Yeah, I agree. But the language is silly. I just leave the type
> > out of foreach and explicitly cast it inside the body.
>
> Thank you all for the concise explanations and suggestions, I
> think that's fairly straightforward. I thought perhaps I was
> doing the sensible thing of dealing with the conversion inside
> the foreach statement, but I guess not!

Well, you were really doing the equivalent of simply declaring a variable
without a cast. e.g.

int i = arr.length;

rather than

int i = cast(int)arr.length;

In general, if the compiler treated giving the foreach variable an explicit
type as being a cast, it would make it really easy to screw up and
unknowingly give a different type than the actual type of the values and end
up with an invisible cast, which could cause subtle bugs.

IIRC, the only case where foreach treats giving an explict type as anything
like a cast is when you're iterating over a string type, and you give a
character type different from the character type of the string. In that
case, it actually decodes the string from one Unicode encoding and encodes
it in the other. Whether the language should have done that rather than
requiring that a library solution be used is debatable (I believe that it
far predates Phobos having the Unicode handling that it does now), but at
least it can't result in stuff like silent truncation. Worst case, it has a
silent performance hit, or you get an unexpected UnicodeException at runtime
due to invalid Unicode.

- Jonathan M Davis





Re: Alternative to Interfaces

2019-01-18 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, January 18, 2019 8:08:47 AM MST Kagamin via Digitalmars-d-learn 
wrote:
> On Friday, 18 January 2019 at 00:08:00 UTC, 1001Days wrote:
> > It works, but I have two questions regarding its efficacy: is
> > it viable in the long run, and is it now possible to use
> > delegates without the GC?
>
> GC is just a handy memory management approach, it even works for
> C and C++, (example: gcc), nothing in D needs GC if you manage
> memory in a different way. In fact there are D libraries that
> rely solely on manual memory management.

Yes, but some D features will use the GC, and you can't really stop that
aside from simply not using those features. The list of such features is
short, but delegates are on it. scope will get around the allocations in
some cases, but in general, if you use delegates, you're going to allocate
with the GC. There are alternatives to using delegates which will get you
similar behavior allocating (e.g. functors), but the allocations that happen
for delegates and lambdas is one of the biggest reasons that some folks
avoid std.algorithm and complain that it allocates. That's what happens when
you pass stuff that the compiler decides has to have closures allocated for
it. Completely avoiding the GC with D is possible, but it tends to require
that you be very careful and have a good understanding of where D needs to
use the GC to do what it does (though the fact that we now have @nogc, and
it screams at you if the code allocates does help you catch GC usage when
you didn't realize that it was there).

- Jonathan M Davis





Re: Runtime heterogeneous collections?

2019-01-17 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, January 17, 2019 1:21:41 AM MST Dukc via Digitalmars-d-learn 
wrote:
> On Thursday, 17 January 2019 at 02:27:20 UTC, Neia Neutuladh
>
> wrote:
> > 1. Make a wrapper class. Now you can store Object[], or you can
> > make a
> > base class or base interface and use that.
> > 2. Use Variant, which can wrap anything, or the related
> > Algebraic, which
> > can wrap a fixed collection of types.
>
> 3. Use an union. However, only do this if you always know from
> outside what type of data is stored in each node. If you need to
> memoize the type of data for each node, better resort to 1. or 2.

Variant types are really just user-friendly wrappers around unions. So,
pedantically, using a variant type such as Variant or Albegbraic and using a
union are fundamentally the same thing, though obviously, the actual usage
in terms of the code that you write is not the same, since if you use a
union directly, you have to deal with the union directly (including figuring
out how to know which type the union currently holds), whereas with a
Variant, you're using its API rather than dealing with the union directly.
In general, it's probably better to use Variant rather than union simply
because Variant deals with the type safety for you.

- Jonathan M Davis





Re: Compile time opAssign/@property constraints

2019-01-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, January 4, 2019 4:50:30 AM MST Jacob Shtokolov via Digitalmars-d-
learn wrote:
> On Friday, 4 January 2019 at 11:41:59 UTC, Simen Kjærås wrote:
> > The thing is, compile-time tests like static if and static
> > assert can only test values that are known at compile-time, and
> > are for the most part useful only in templates.
>
> Thanks for this answer! That's sad to hear.
> But, is there anything to do with CTFE? Can it help somehow in
> such situation?

CTFE is the compile-time evaluation of functions. You're calling a function
at compile time. How the function works is basically the same as how it
works at runtime. There are some caveats because of how the CTFE engine
works (e.g. pointer arithmetic isn't legal at compile time), but the
function itself is called normally. Something like a static assertion is run
when the function itself is compiled - which must happen before that
function is used during CTFE. So, you can do something like

auto foo(int i)
{
static assert(someFunc() == 42);
...
}

but you can't do something like

auto foo(int i)
{
static assert(someFunc() == i);
...
}

because that would be mixing compile time and runtime stuff. Even if foo is
called at compile time, it's compiled before it's called, and the static
assertion is part of its compilation process, not part of running it, and
runtime variables aren't available when the function is being compiled. So,
if you did

auto foo(int i)
{
assert(someFunc() == i);
...
}

and then called foo with CTFE, then that assertion would be run as part of
running foo just like it would be at runtime, but a static assertion
wouldn't make sense. CTFE doesn't fundamentally change what is a
compile-time and what is a runtime constructs. It just allows functions to
be called at compile time so that you can do stuff like initialize values
that are generated at compile time.

Unfortunately, the wiki seems  be down right now, but once it's back up, I
suggest that you read

https://wiki.dlang.org/User:Quickfur/Compile-time_vs._compile-time

IIRC, it's still a work in progress, but it should give you a much clearer
idea of how CTFE fits into things.

- Jonathan M Davis






Re: DIP 1000 and classes

2019-01-03 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, January 3, 2019 3:28:35 AM MST Nordlöw via Digitalmars-d-learn 
wrote:
> How does DIP 1000 treat the lifetime scoped class parameters and
> containers of classes?

scope isn't transitive, and putting an object inside a container would be
escaping it, which would violate scope. So, you could have a container that
was scope, but you couldn't put anything that's scope inside of it.

- Jonathan M Davis






Re: Qualified class opEquals()

2018-12-27 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, December 25, 2018 7:27:39 AM MST Per Nordlöw via Digitalmars-d-
learn wrote:
> On Tuesday, 25 December 2018 at 00:32:55 UTC, Paul Backus wrote:
> > No, because equality comparison between classes lowers to
> > `object.opEquals` [1], which takes both parameters as `Object`.
>
> This is a severe limitation. Are there any plans on fixing this
> or do I have to wait for Andrei's proposed ProtoObject?

ProtoObject _is_ the proposed fix, but if you want to use Object's opEquals
in @safe code, you can always create a wrapper function that's marked
@trusted and call that instead.

- Jonathan M Davis






Re: Temporary @trusted scope

2018-12-19 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, December 19, 2018 1:19:42 AM MST rikki cattermole via 
Digitalmars-d-learn wrote:
> On 19/12/2018 7:11 PM, Jonathan M Davis wrote:
> > Really? I would have thought that that would be a pretty obvious
> > optimization (especially if inlining is enabled).
>
> Assembly doesn't lie.

I'm not saying that you're wrong, just expressing surprise. I've never
checked to see what code actually got generated. But I do think that it's
something that the compiler should be smart enough to do even if it isn't
currently that smart, and the fact that it isn't is most defintely not a
good thing.

- Jonathan M Davis





Re: Checking if CTFE is used?

2018-12-18 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, December 18, 2018 9:20:11 AM MST berni via Digitalmars-d-learn 
wrote:
> On Tuesday, 18 December 2018 at 14:32:29 UTC, Adam D. Ruppe wrote:
> > CTFE is used if and only if it MUST be used by context. That's
> > a runtime function, so no ctfe.
> >
> > Do something like:
> >
> > int[4] generate() {
> >
> >int[4] tmp;
> >foreach(i; 0..4) tmp[i] = i;
> >return tmp;
> >
> > }
> >
> >
> > static immutable int[4] clue = generate();
>
> Great, that worked. :-) My reasoning was, that CTFE is somewhat
> greedy, that is, everything that can be evaluated at compile time
> will be evaluated at compile time...
>
> Many thanks for your replies. :-)

It's pretty much the opposite. CTFE is only ever done when the compiler
needs the result at compile-time, and it's never done as an optimization, if
nothing else because the compiler has no way of knowing whether the function
is even CTFE-able until it actually tries. Having it attempt CTFE in a bunch
of places and then give up (to then call the function at runtime instead)
would likely have a very negative impact on compilation time - especially
since CTFE isn't very efficient at the moment (though whenever the newCTFE
that Stefan is working on finally lands, that should improve significantly).
As things stand, you have complete control over when CTFE occurs, and it's
usually pretty easy to figure out if it's happening or not. As long as you
understand which things must be known at compile-time, it's straightforward.

- Jonathan M Davis





Re: Temporary @trusted scope

2018-12-18 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, December 18, 2018 5:42:12 AM MST rikki cattermole via 
Digitalmars-d-learn wrote:
> On 19/12/2018 1:34 AM, Per Nordlöw wrote:
> > On Tuesday, 18 December 2018 at 10:42:51 UTC, Jonathan M Davis wrote:
> >> Unfortunately, D does not currently have a way to do that. Only
> >> functions can be marked with @trusted. However, the typical approach
> >> to this problem is to use a lambda, which is more or less
> >> syntactically the same except that it has some extra parens. e.g.
> >>
> >> () @trusted { doUnsafe(); }();
> >
> > Is there a performance hit when using this?
>
> Yes except for ldc with -O3.
> But it is a function not a delegate so it should be all nicely
> prefetched and ready to go. So I wouldn't worry about it too much.

Really? I would have thought that that would be a pretty obvious
optimization (especially if inlining is enabled). I suppose that it doesn't
entirely surprise me if dmd does a poor job of it, but I would have expected
ldc to do better than that. I would think that such an improvement would be
pretty low-hanging fruit for adding to dmd's optimizer though. If not, it
sounds like further justification for adding a feature for this rather than
having to use a lambda. Aside from that though, the lambda trick is simple
enough that it wouldn't surprise me if Walter and Andrei's response to such
a DIP would be to just use the lambda trick.

- Jonathan M Davis






Re: Temporary @trusted scope

2018-12-18 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, December 18, 2018 3:14:50 AM MST Per Nordlöw via Digitalmars-d-
learn wrote:
> What's the preferred way of creating a temporary @trusted scope
> without writing a separate  function?
>
> Similar to Rust's
>
> unsafe { /* unsafe stuff here */ }

Unfortunately, D does not currently have a way to do that. Only functions
can be marked with @trusted. However, the typical approach to this problem
is to use a lambda, which is more or less syntactically the same except that
it has some extra parens. e.g.

() @trusted { doUnsafe(); }();

or

auto result = () @trusted { getUnsafe:() }();

So, it's less than ideal, but it gets us close, and unless the code is long
enough that maybe it should be in its own function, it's better than
declaring a nested function, let alone declaring an entirely separate
function at module scope.

- Jonathan M Davis






Re: Shared static this() not executed for unittest

2018-12-17 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, December 16, 2018 12:53:43 PM MST Steven Schveighoffer via 
Digitalmars-d-learn wrote:
> On 12/15/18 5:14 PM, Jonathan M Davis wrote:
> > On Saturday, December 15, 2018 10:27:36 AM MST Neia Neutuladh via
> >
> > Digitalmars-d-learn wrote:
> >> On Sat, 15 Dec 2018 17:19:05 +, Timoses wrote:
> >>> Running `dub test` will output:
> >>> Running ./unit-test-library writeln: unittest All unit tests have been
> >>> run successfully.
> >>>
> >>> Why is the `shared static this()` not executed?
> >>
> >> Run `dub clean; dub test -v` and you'll see that main.d isn't compiled
> >> into the test library.
> >>
> >> dub test substitutes its own main() function over yours. In order to do
> >> this, it needs to not compile in your main() and to compile in its own.
> >> dmd doesn't have an option to replace main(), so dub drops that entire
> >> source file.
> >
> > Yeah. I hate how dub does this. I've been bitten by it on multiple
> > occasions, and it's really easy to miss that this is happening. It
> > probably would have been better if it required you to deal with main
> > when the target type is an executable, resulting in a linker error when
> > you didn't provide one. Instead, a number of us do stuff like
>
> This should be fixed, as DMD now supports just running the program with
> --DRT-testmode=test-only and it will only run unit tests.

That would be fantastic.

- Jonathan M Davis





Re: Shared static this() not executed for unittest

2018-12-15 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, December 15, 2018 10:27:36 AM MST Neia Neutuladh via 
Digitalmars-d-learn wrote:
> On Sat, 15 Dec 2018 17:19:05 +, Timoses wrote:
> > Running `dub test` will output:
> > Running ./unit-test-library writeln: unittest All unit tests have been
> > run successfully.
> >
> > Why is the `shared static this()` not executed?
>
> Run `dub clean; dub test -v` and you'll see that main.d isn't compiled
> into the test library.
>
> dub test substitutes its own main() function over yours. In order to do
> this, it needs to not compile in your main() and to compile in its own.
> dmd doesn't have an option to replace main(), so dub drops that entire
> source file.

Yeah. I hate how dub does this. I've been bitten by it on multiple
occasions, and it's really easy to miss that this is happening. It probably
would have been better if it required you to deal with main when the target
type is an executable, resulting in a linker error when you didn't provide
one. Instead, a number of us do stuff like

version(unittest) void main() {}
void main()
{
...
}

thinking that it's working, but whatever tests in the module with main
simply don't get run, because that module isn't compiled in. Maybe dub
should check the module with main to see if it contains any unittest blocks
and print out warning if it does, but even if it did, it actually wouldn't
have caught this case, because it involves a static constructor, not a
unittest block.

Anyway, the way that dub deals with this probably makes it so that the best
thing to do in general is to make it so that the module with main is pretty
much literally something like

int main(string[] args)
{
import somemodulename;
return realmain(args);
}

But of course, that just makes it so that you're less likely to accidentally
do something like create a static this which won't be called with -unittest
when you already know that that sort of thing is a problem with dub test. It
doesn't help those folks who aren't aware of this behavior or who forget it.

- Jonathan M Davis





Re: Bug in shifting

2018-12-13 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, December 13, 2018 6:56:33 PM MST Steven Schveighoffer via 
Digitalmars-d-learn wrote:
> On 12/13/18 7:16 PM, Michelle Long wrote:
> > I've noticed the compiler is not throwing up errors and warnings like it
> > used to:
> >
> > I thought D required breaks for cases? Seems it doesn't any longer! I'm
> > only using -g -gf -d
>
> It doesn't require breaks for cases, it requires no fall-through on
> cases. Again, an example would help describe what you mean.

Well, to be more precise, it doesn't allow fallthrough when the case
statement contains code. It will allow it when it doesn't. e.g.

case 0:
case 1: break;

is perfectly legal. However, when the case statement contains code, then
yeah, some form of control statement is required to exit the case statement,
but that's a lot more than just break. continue, goto, return, etc. can all
be used to exit a case statement. Any control statement that explicitly
exits the case statement will work. And of course, goto case can be used for
explicit fallthrough.

- Jonathan M Davis





Re: OT (Was: Re: is(ElementType!(char[2]) == dchar - why?)

2018-12-11 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, December 11, 2018 2:11:49 PM MST H. S. Teoh via Digitalmars-d-
learn wrote:
> On Tue, Dec 11, 2018 at 09:02:41PM +, bauss via Digitalmars-d-learn 
wrote:
> > On Tuesday, 11 December 2018 at 18:10:48 UTC, H. S. Teoh wrote:
> [...]
>
> > > Autodecoding raises its ugly head again. :-/
>
> [...]
>
> > Has it ever had anything else?
>
> LOL... well, we (or some of us) were deceived by its pretty tail for a
> while, until we realized that it was just a façade, and Unicode really
> didn't work the way we thought it did.

Yeah. Auto-decoding came about, because Andrei misunderstood Unicode and
thought that code points were complete characters (likely because the
Unicode standard weirdly likes to refer to them as characters), and he
didn't know about graphemes. At the time, many of us were just as clueless
as he was (in many cases, more so), and auto-decoding made sense. You
supposedly got full correctness by default and could work around it for
increased performance when you needed to (and the standard library did that
for you where it mattered, reducing how much you had to care). Walter knew
better, but he wasn't involved enough with Phobos development to catch on
until it was too late. It's only later when more folks involved came to a
fuller understanding of Unicode that auto-decoding started to be panned.

For instance, I very much doubt that you would find much from the D
community talking about how horrible auto-decoding is back in 2010, whereas
you probably could find plenty by 2015, and every time it comes up now,
folks complain about it. Previously, folks would get annoyed about the
restrictions, but the restrictions made sense with the understanding that
code points were the actual characters, and you didn't want code to be
chopping them up. But once it became more widely understood that code points
were also potentially pieces of characters, you no longer had the same
defense against the annoyances caused by how narrow strings are treated, and
so it just became annoying. We went from newcomers getting annoyed, but
those who understood the reasons behind auto-decoding being fine with it
(because it supposedly made their code correct and prevented bugs) to almost
everyone involved being annoyed about it. The newcomers who don't understand
it still get annoyed by it, but instead of the ones who do understand it
telling them about how it's helping keep Unicode handling correct, the folks
who understand what's going now tell everyone how terrible auto-decoding is.

So, the narrative that auto-decoding is terrible has now become the status
quo, whereas before, it was actually considered to be a good thing by the D
community at large, because it supposedly ensured Unicode correctness. It
was still annoying, but that was because Unicode is annoying. Now, Unicode
is still annoying, but auto-decoding is understood to make it even more so
without actually helping.

The one bright side out of all of this that makes it so that I don't think
that auto-decoding is entirely bad is that it shoves the issue in everyone's
faces so that everyone is forced to learn at least the basics about Unicode,
whereas if we didn't have it, many folks would likely just treat char as a
complete character and merrily write code that can't handle Unicode, since
that's what usually happens in most programs in most languages (some
languages do use the equivalent of wchar for their char, but most code still
treats their char type as if it were a complete character). The fact that we
have char, wchar, and dchar _does_ help raise the issue on its own, but
auto-decoding makes it very hard to ignore. Now, that doesn't mean that I
think that we should have auto-decoding (ideally, we'd figure out how to
remove it), but the issues that it's caused have resulted in a lot of
developers becoming much more knowledgeable about Unicode and therefore more
likely to write code that handles Unicode correctly.

- Jonathan M Davis






Re: Working with ranges

2018-12-07 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, December 7, 2018 8:46:11 PM MST Adam D. Ruppe via Digitalmars-d-
learn wrote:
> On Saturday, 8 December 2018 at 03:37:56 UTC, Murilo wrote:
> > Hi guys, I have created an array of strings with "string[12] ps
>
> string[12] isn't a range, but string[] is.
>
> Try passing `ps[]` to the function instead of plain `ps` and see
> what happens.

Specifically, the problem is that static arrays have a fixed length, which
means that you can't pop elements off as is required for ranges. Dynamic
arrays on the other hand are ranges (at least as long as you import
std.range.primitives to get the range functions for dynamic arrays). Slicing
a static array gives you a dynamic array which is a slice of the static
array. So, mutating the elements of the dynamic array will mutate the
elements of the static array, but the dynamic array can have elements popped
off as is required for ranges, whereas the static array can't.

- Jonathan M Davis





Re: Writing Program Without main Function

2018-12-07 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, December 7, 2018 2:42:33 PM MST Samir via Digitalmars-d-learn 
wrote:
> Ok.  Upon further investigation, I think I see what is going on.
> Most of the repos I am skimming are for this year's Advent of
> Code.  They structure their repo with an `app.d` file which does
> contain a `main` function but this program is structured such
> that it imports the files I was looking at earlier (which do not
> have a `main` function).
>
> Looks like I have to get smarter on how modules, mixins and
> imports work.

There's one main per program, not per module. Where main lives depends on
how the program was written, but dub encourages putting it in app.d, because
that's what it generates when you create a new dub project. imports then
provide access to other modules so that the code doing the importing can use
it. You can think of it like the module with main being the start of the
import tree, though it's a bit more complicated than that in practice, since
modules can be compiled separately, and main only has to be there when the
program is finally linked. But in concept, you have main and the module its
in importing other modules, which then import other modules, etc. until you
get all of the code in the program.

- Jonathan M Davis





Re: Writing Program Without main Function

2018-12-07 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, December 7, 2018 2:02:59 PM MST Samir via Digitalmars-d-learn 
wrote:
> Is it possible to write and execute a D program without a main
> function?
>
> Most of my programs will start with some `import` statements,
> followed by any functions and then ending with the `main`
> function (e.g. `void main() {`).
>
> As I am just a beginner to programming and still new to D, I have
> been browsing some repositories that people have posted here to
> learn more about the language and how more experienced
> programmers write their code.  In many of these examples, they
> start with the `module` statement followed by their `import`
> statements and then will have sections defining various classes,
> structs, unit tests and other bits but I never see a `main`
> function.
>
> How do you compile and execute these programs?

The short answer is that every program must have a main function.

The long answer:

main is the entry point into the program. You can't do much without it, and
the linker will require that it exists. static constructors do get run
before main, and static destructors get run after it, so it is possible to
run code before and after main, but they're only intended for more complex
initialization and destruction of module-level and static variables. Really,
when it comes down to it, main _is_ your program, and there must be a main
function one way or another. That's true of pretty much any programming
language. Some may present main in a different way, but ultimately, every
programming language has some form of main, because every program needs an
entry point.

dmd provides the -main flag which will insert an empty main, so you could
use that, but it's really only of any use for unit testing (since in D,
unittest blocks are run before main). For an actual program, you basically
don't have anything without main. Essentially what you get in D is

1. Run static constructors.
2. If -unittest was used, run the unittest blocks (though since that's only
   intended for testing, it really shouldn't be in a production program).
3. Run main.
4. Run static destructors.

And for simpler programs, you basically have

1. Run main.

None of your stray functions or classes are going to be used just because
you declared them. It's main that decides what's going to be run, even if
it's just to call another function. All of those other functions and classes
are just a way to organize your program, make pieces reusable, etc.
Ultimately, the main function is your program, so it really doesn't make
sense to try to not have one.

The closest thing that exists to a program with no main is a library, and
libraries are just collections of functions and user-defined types which are
packaged together so that programs can use them. They aren't programs on
their own, just pieces of reusable code. Ultimately, you need an actual
program with a main to use them.

When you see code snippets that don't use main, it's because they're usually
just that - code snippets. They're showing a piece of code, not an entire
program. It's just assumed that anyone who wants to actually run them is
going to deal with declaring main themselves, because everyone knows that
you need a main function. As such, including main is often just extraneous
information.

- Jonathan M Davis





Re: int[] as constructor

2018-12-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, December 4, 2018 3:17:04 PM MST jmh530 via Digitalmars-d-learn 
wrote:
> I've noticed that I can use int like a constructor, as in:
>  int x = int(1);
> but I can't do the same thing with slices
>  int[] y = int[]([1, 2]);
>
> Is there something I'm missing here or is this a potential
> enhancement? It can make some types of generic code a little more
> annoying.

Using parens with dynamic arrays already has a different meaning. It's how
you provide the size of the dynamic array. e.g.

auto x = int[](12);

or

auto x = int[][](3, 4);

In the first level, you can put the number in between the brackets instead -
e.g.

auto x = int[12];

but that falls apart at deeper levels, because the number in between the
brackets would then mean a static array (making it so that you have a
dynamic array of a static array). So, in the general case, parens are how
you provide a dynamic array's length. This was true long before it became
possible to use parens for construction with built-in types like you do with
user-defined types.

- Jonathan M Davis





Re: .dup vs operation on all elements

2018-12-03 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, December 3, 2018 1:07:24 PM MST Goksan via Digitalmars-d-learn 
wrote:
> Are there any differences between these 2 methods of copying
> elements?
>
> double[] array = [ 1, 20, 2, 30, 7, 11 ];
>
> // Non dup
> double[6] bracket_syntax_dup = array;
> bracket_syntax_dup[] = array;
> bracket_syntax_dup[0] = 50;
>
> // Dup
> double[6] normal_dup = array.dup;
> normal_dup[0] = 100;
>
> OUTPUT: (array, bracket_syntax_dup and normal_dup respectively):
> [1, 20, 2, 30, 7, 11]
> [50, 20, 2, 30, 7, 11]
> [100, 20, 2, 30, 7, 11]

dup allocates a new dynamic array and copies the elements of the existing
dynamic array to the new one. Calling dup in order to assign to a static
array is just needlessly allocating a dynamic array. The contents of the
array are going to be copied to the static array regardless, but instead of
just copying the elements, if you use dup, you're allocating a new dynamic
array, copying the elements into that dynamic array, and then you're copying
the elements into the static array. There's no point.

You use dup when you want to copy the elements of a dynamic array instead of
simply slicing it. Slicing gives you a new dynamic array that points to
exactly the same elements. It's just copying the pointer and the length
(meaning that mutating the elements of the new slice will affect the
elements in the original array), whereas dup actually allocates a new block
of memory for the new dynamic array to be a slice of (copying the elements
over in the process), so mutating the elements in the new dynamic array then
won't affect the elements in the original.

Regardless, when you create a static array, it's not a slice of anything
(since its elements sit directly on the stack), and when assign to it,
you're simply copying the elements over.

- Jonathan M Davis





Re: gcc 9 vs. dmd?

2018-11-30 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, November 30, 2018 2:43:41 AM MST welkam via Digitalmars-d-learn 
wrote:
> On Friday, 30 November 2018 at 04:47:26 UTC, Andrew Pennebaker
>
> wrote:
> > gcc is currently required for dmd on FreeBSD, as dmd links to
> > libstdc++.
>
> Parts of dmd are still written in C++ but most of it was
> converted recently. More on that here:
> "DMD backend now in D"
> https://forum.dlang.org/thread/psaekt$tah$1...@digitalmars.com

That and the C/C++ compiler could be clang rather than gcc. Even without the
backend being ported to D, there shouldn't be an actual dependency on gcc
specifically (especially on FreeBSD where you may not even have gcc
installed). But if I understand correctly, dmd has always used the C
compiler to link on *nix systems rather than using the linker directly. I
don't know why it does, but linking via the C compiler is a completely
different issue from integrating with it.

Regardless, as to the OP's question about gcc integration, that really
doesn't have much to do with dmd. That's a big step forward for gdc, but dmd
is the reference compiler. It's where everything is implemented. gdc and ldc
are then alternate compilers that use the same front-end. but they're
separate projects, and there's really no benefit to us at this point to
removing dmd in favor of either of the other two. With dmd, we're in full
control of the code and the release cycle, which is not true with llvm or
gcc. Honestly, as great as it is for gdc to end up in the official gcc
release, in practice, I expect that it's going to be a recipe for a portion
of the community using an outdated version of the language (especially when
coupled with stuff like LTS releases for Linux distros). That's already been
a problem with gdc even without it being in the official gcc release due to
how long it's taken them to catch up after the front-end was converted to D.

Also, dmd's backend is the backend that Walter wrote and has used for
decades - and it's part of dmc, which he still sells. So, I don't think that
he's going to be in hurry to drop it. And if he were, I honestly expect that
ldc would have become the reference compiler a while ago, not gdc. But dmd
continues to be the reference compiler, and while improving its backend is
not the focus, Walter still does work on it (and part of the reason that
he's converted it to D is so that he can more easily improve it).
Historically, Walter has wanted to stay away from gcc and clang code (or the
code of any other compiler that isn't his), because in the past, he's found
that being able to say that he's never read the source code has been a good
defense against any kind of accusation of code stealing (which definitely
matters when he's selling a C++ compiler). So, all the signs are that we're
going to continue to have the choice of dmd, ldc, and gdc, and none of them
are going anywhere.

- Jonathan M Davis





Re: version(StdDoc)

2018-11-25 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, November 24, 2018 10:41:56 PM MST H. S. Teoh via Digitalmars-d-
learn wrote:
> On Sat, Nov 24, 2018 at 05:48:16PM +, Stanislav Blinov via 
Digitalmars-d-learn wrote:
> > On Saturday, 24 November 2018 at 17:43:35 UTC, Jonathan M Davis wrote:
> > > I'm still inclined to think though that it should be legal to just
> > > use version directly in the member list.
> >
> > Yup. UDAs did get in there eventually, and version should too.
>
> I think this would be a trivial DIP, by making it such that a version
> block inside an enum would lower to the above code. Of course, it could
> be taken further: the above trick doesn't quite handle this case:
>
>   enum E {
>   a,
>   version(Windows) {
>   b, c
>   }
>   version(Posix) {
>   d
>   }
>   }
>
> But this looks like such an antipattern that it probably should be
> written differently anyway, or just generated via a string mixin.

It's something that comes up fairly frequently actually when dealing with
system APIs. For instance, if you want your socket API to provide the full
functionality of the underlying C API, then you're going to have to provide
not only differing enum values for things like socket options or socket
family, but you're actually going to have to provide different enum members
in some cases.

So, sure, if you're writing something that's purely D and can be properly
platform-agnostic, then having different enum members for different
platforms would be bad, but once C APIs get involved, I definitely would not
consider it to be an anti-pattern. At that point, it has a tendency to
become a necessity, and I've had several occasions where being able to
version enum members would have made the code shorter. It also would have
eliminated the need for version(D_Ddoc) (or the druntime or Phobos
equivalents).

- Jonathan M Davis





Re: version(StdDoc)

2018-11-24 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, November 24, 2018 9:28:47 AM MST Stanislav Blinov via 
Digitalmars-d-learn wrote:
> On Saturday, 24 November 2018 at 07:00:31 UTC, Jonathan M Davis
>
> wrote:
> > [not legal]
> >
> > enum Foo
> > {
> >
> > a,
> > b,
> > version(linux) c = 42,
> > else version(Windows) c = 54,
> >
> > }
> >
> > You're forced to version the entire enum.
>
> Not in this case, no:
>
> enum Foo
> {
>  a,
>  b,
>  c = {
> version(linux) return 42;
> else version(Windows) return 54;
>  } ()
> }
>
> /pedantry

LOL. That's an interesting trick. It's ugly and hacky, but it does work
around the problem. I'm still inclined to think though that it should be
legal to just use version directly in the member list.

- Jonathan M Davis





Re: version(StdDoc)

2018-11-23 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, November 23, 2018 11:22:24 PM MST Neia Neutuladh via Digitalmars-
d-learn wrote:
> On Fri, 23 Nov 2018 21:43:01 -0700, Jonathan M Davis wrote:
> > A solution like that might work reasonably well, but you still
> > have the problem of what to do when a symbol is documented in multiple
> > version blocks, and having almost all the documentation in one version
> > block and a few pieces of it in other version blocks would risk getting
> > confusing and messy.
>
> Keeping symbol names and function arguments consistent between them is
> also an issue; it's not just the documentation. The normal solution is to
> put the version blocks inside the relevant symbols -- sometimes type
> aliases inside version blocks and consistent code outside, sometimes
> functions where the entire body is a set of version blocks.

When you're versioning the implementation, it's trivial to just version the
function internals. Where version(D_Ddoc) becomes critical is with stuff
like structs or enums where the members actually differ across systems. And
while it's generally better to try to avoid such situations, there are
definitely situations where there isn't much choice. Fortunately, in the
vast majority of situations, versioning across systems isn't required at
all, and in most of the situations where it is, its only the implementation
that needs to differ, but that's not true in all cases.

I do wish though that it were legal to use version blocks in more situations
than is currently the case. For instance,

enum Foo
{
a,
b,
version(linux) l,
else version(Windows) w,
}

is not legal, nor is

enum Foo
{
a,
b,
version(linux) c = 42,
else version(Windows) c = 54,
}

You're forced to version the entire enum. Fortunately, structs and classes,
do not have that restriction, so having to version an entire struct or class
at once is usually only required when the type needs to be declared on some
systems but not others (as is the case with WindowsTimeZone), and such
situations are rare.

- Jonathan M Davis





Re: D is supposed to compile fast.

2018-11-23 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, November 23, 2018 11:13:24 AM MST H. S. Teoh via Digitalmars-d-
learn wrote:
> All in all, though, the fact that we're complaining about extra seconds
> in compilation times still does show just how fast D compilation can be.
> In the old days, compiling large C++ codebases usually means 30 mins to
> 2 hours, and a few extra seconds won't even be noticed.  I haven't
> checked C++ compile times recently, though -- things may have improved
> since I last seriously used C++.

When I was a student, I worked for a while at a company that had a large C++
code base that took over 3 hours to compile from scratch (incremental builds
were an absolute must). I ended up working somewhere else for a while and
then coming back again, and in the interim, they had begun redoing the
program in Java. The build process then took about 10 minutes, and folks
were complaining about it taking too long. After having been away for a
while, my perspective was that it was a _huge_ improvement, but since they'd
been working with it for a while, the 10 minutes was annoying. So, a lot of
it comes down to perspective.

D is often a _huge_ improvement when you first switch to it, but depending
on what your code does, over time, it can go from under a second to a few
seconds in compilation time, and for some folks that becomes maddening in
spite of the fact that the overall build times are a huge improvement over
what they would have had in another language - and usually, the features
that slow down the build the most are ones that don't even exist in other
languages (or if they do, are far less powerful). That being said, if we can
reasonably improve the compiler and standard library such that D code in
general builds faster with all of the CTFE and templates, we definitely
should.

- Jonathan M Davis





Re: version(StdDoc)

2018-11-23 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, November 23, 2018 7:55:04 PM MST H. S. Teoh via Digitalmars-d-
learn wrote:
> Adam does have a very good point about showing all alternatives to docs,
> though.  Arguably, that's what ddoc *should* do.  If the programmer
> wrote a ddoc comment in the code, it probably should be processed as
> part of doc generation, regardless of whether that code sits in some
> deeply-nested version blocks that ends up not being compiled.  Binding
> ddoc generation to the compile process seems not such a good idea in
> retrospect.

Honestly, I would argue that if you have multiple versions of the
documentation, then there's a serious problem. The documentation shouldn't
be platform-dependent even if the symbols are. Even if the documentation
needs some extra notes for a specific platform, it should all be in one
documentation block that anyone using the symbol can read. Providing
different documentation for different platforms just leads to folks not
understanding how the symbol differs across platforms, leading to code that
is even more platform-dependent when it really should be as platform
independent as possible.

The only situation I can think of at the moment where anything along the
lines of combining documentation across platforms makes sense would be if
there is a nested symbol that exists on only one platform (e.g. a member
function of a struct or a member of an enum). In that case, one platform
would have the main documentation, and then system-specific symbols would be
documented in those version blocks - but only those symbols. A solution like
that might work reasonably well, but you still have the problem of what to
do when a symbol is documented in multiple version blocks, and having almost
all the documentation in one version block and a few pieces of it in other
version blocks would risk getting confusing and messy. As such, I'm not sure
that the fact that ddoc forces you to have a separate set of declarations
just for the documentation is really a bad thing. It puts all of the
documentation in one place.

The bigger problem IMHO is how -D affects the build. Both it and -unittest
have the fundamental problem that because they create their own version
identifiers, they really shouldn't be part of the normal build, and yet the
way that they're set up to be used, it's as if they're expected to be part
of the normal build - with -D just causing the compiler to generate the
documentation in addition to the binary, and -unittest making the unit tests
run before main rather than replacing main.

At this point, I really wish that at minimum, -D were not set up to be part
of the normal build process so that version(D_Ddoc) would not affect it. The
same with -unittest. Ideally, it really would have replaced main rather than
putting the unit tests before it, with it providing main if one wasn't
there. That still doesn't solve all of the problems when using
version(unittest), but I doubt that much of anyone really wants to be
running unit tests as part of their application, and having such flags
clearly designed to create special builds rather than being designed such
that they could be used with the normal build would have fixed certain
classes of problems.

As for the issue of versioning the documentation, I don't really see a clean
one. Having the documentation build affected by version and static if and
the like causes some problems, but having it ignore them would likely cause
other problems. Regardless, I suspect that having the version identifiers
and static ifs be ignored almost requires a separate tool from the compiler
(such as Adam's documentation generator or ddox), because it's pretty clear
that ddoc was set up to generate the documentation for symbols as the
compiler compiles them, whereas a tool that ignored version identifiers and
static ifs would be processing the file quite differently.

- Jonathan M Davis





Re: version(StdDoc)

2018-11-23 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, November 23, 2018 2:47:51 PM MST Tony via Digitalmars-d-learn 
wrote:
> In std.compiler there is this code:
>
>  /// Which vendor produced this compiler.
>  version(StdDdoc)  Vendor vendor;
>  else version(DigitalMars) Vendor vendor = Vendor.digitalMars;
>  else version(GNU) Vendor vendor = Vendor.gnu;
>  else version(LDC) Vendor vendor = Vendor.llvm;
>  else version(D_NET)   Vendor vendor = Vendor.dotNET;
>  else version(SDC) Vendor vendor = Vendor.sdc;
>  else  Vendor vendor = Vendor.unknown;
>
> What is the situation in which the identifier StdDoc is set?

It's a Phobos-only replacement for the D_Ddoc version identifier and is
defined as part of the Phobos build. As the others have been complaining
about in this thread, ddoc is set up so that it takes whatever version is
currently being compiled. So, version(D_Ddoc) is the standard way to provide
documentation that is agnostic of the platform in the cases where a
documented symbol doesn't exist on all platforms, or its definition differs
such that it needs separate declarations - e.g. if the values of members in
an enum differ across systems, then you're forced to provide completely
separate enum declarations for the entire enum. If you have separate
declarations on different platforms, then in general there are only three
choices

1. Duplicate the documentation.

2. Set it up so that your documentation can only be built on one platform.

3. Use version(D_Ddoc) to provide a separate declaration just for the
documentation.

There are some cases where you can put the documentation outside the version
block and have it work - e.g.

/// my documentation
version(linux) int foo(string bar) { ... }
else version(Windows) int foo(string bar) { ... }
else ...

but that only works when you only need to document the top-level symbol
(such as with a function). It does not work with anything that needs to have
symbols inside it documented (such as with a struct, class, or enum).

Fortunately, most code does need to be versioned like this (especially if
you're trying to write platform-independent code like we try to do with
Phobos), and often, when you do need to version stuff, it's inside
implementations, but sometimes it does affect the top level. std.file has
this problem in a few places as does std.datetime with WindowsTimeZone
(since it only exists on Windows). The solution the language provides is to
use version(D_Ddoc) to version such documentation. And that's what Phobos
used to do.

The problem is that once you start using version(D_Ddoc), you _must_ have a
separate documentation build. You can't build your documentation as part of
your normal build, because you'd be getting the version(D_Ddoc) stubs
instead of the correct implementation for your platform (or instead of
nothing at all if that platform isn't supposed to have that particular
symbol). Phobos already had a separate documentation build because of how it
generates the documentation for the website, but many people's projects do
not. Most projects don't ever need to use version(D_Ddoc), because they
don't have symbols that are platform-dependent, and so before Phobos started
using it, they could compile their documentation as part of their normal
build just fine, because version(D_Ddoc) wasn't in their code anywhere. But
as soon as Phobos started using it, their code broke. If they had had a
separate documentation build, then they wouldn't have had any problems, but
as it was, their code was broken.

So, for better or worse, rather than saying that it was just bad practice to
do the documentation build as part of your normal build (and I would
strongly argue that building the documentation as part of the normal build
is bad practice given how doing so defines a new version identifier that can
affect the build), it was decided that Phobos would stop using
version(D_Ddoc) as the language intended and instead use its own custom,
version identifier for the documentation - which is why we now have
version(StdDoc) in Phobos and version(CoreDdoc) in druntime. With this
change, anyone building with the -D flag as part of their normal build
doesn't end up with version(D_Ddoc) screwing up their code because of
druntime or Phobos. Some other project they depend on could screw it up, and
if they ever use version(D_Ddoc) in their code, they'll have trouble again,
but Phobos and druntime aren't going to mess them up in that regard.

And while version(D_Ddoc) is the standard solution, because of this general
problem with folks using -D with their normal build, it's arguably best
practice at this point to create your own version identifier for your own
documentation for any library that you release that needs to version its
documentation. Otherwise, anyone using your library will have the same
problems that resulted in Phobos switching from version(D_Ddoc) to
version(StdDdoc) - which if anything shows that things 

Re: Why does nobody seem to think that `null` is a serious problem in D?

2018-11-22 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, November 21, 2018 3:24:06 PM MST Johan Engelen via 
Digitalmars-d-learn wrote:
> On Wednesday, 21 November 2018 at 07:47:14 UTC, Jonathan M Davis
>
> wrote:
> > IMHO, requiring something in the spec like "it must segfault
> > when dereferencing null" as has been suggested before is
> > probably not a good idea is really getting too specific
> > (especially considering that some folks have argued that not
> > all architectures segfault like x86 does), but ultimately, the
> > question needs to be discussed with Walter. I did briefly
> > discuss it with him at this last dconf, but I don't recall
> > exactly what he had to say about the ldc optimization stuff. I
> > _think_ that he was hoping that there was a way to tell the
> > optimizer to just not do that kind of optimization, but I don't
> > remember for sure.
>
> The issue is not specific to LDC at all. DMD also does
> optimizations that assume that dereferencing [*] null is UB. The
> example I gave is dead-code-elimination of a dead read of a
> member variable inside a class method, which can only be done
> either if the spec says that`a.foo()` is UB when `a` is null, or
> if `this.a` is UB when `this` is null.
>
> [*] I notice you also use "dereference" for an execution machine
> [**] reading from a memory address, instead of the language doing
> a dereference (which may not necessarily mean a read from memory).
> [**] intentional weird name for the CPU? Yes. We also have D code
> running as webassembly...

Skipping a dereference of null shouldn't be a problem as far as memory
safety goes. The issue is if the compiler decides that UB allows it do to
absolutely anything, and it rearranges the code in such a way that invalid
memory is accessed. That cannot be allowed in @safe code in any D compiler.
The code doesn't need to actually segfault, but it absolutely cannot access
invalid memory even when optimized.

Whether dmd's dead code elimination algorithm is able to make @safe code
unsafe, I don't know. I'm not familiar with dmd's internals, and in general,
while I have a basic understanding of the stuff at the various levels of a
compiler, once the discussion gets to stuff like machine instructions and
how the optimizer works, my understanding definitely isn't deep. After we
discussed this issue with regards to ldc at dconf, I brought it up with
Walter, and he didn't seem to think that dmd had such a problem, but I
didn't think to raise that particular possibility either. It wouldn't
surprise me if dmd also had issues in its optimizer that made @safe not
@safe, and it wouldn't surprise me if it didn't. It's the sort of area where
I'd expect that ldc's more aggressive optimizations to be much more likely
to run into trouble, and it's more likely to do things that Walter isn't
familiar with, but that doesn't mean that Walter didn't miss anything with
dmd either. After all, he does seem to like the idea of allowing the
optimizer to assume that assertions are true, and as far as I can tell based
on discussions on that topic, he doesn't seem to have understood (or maybe
just didn't agree) that if we did that, the optimizer can't be allowed to
make that assumption if there's any possibility of the code not being memory
safe if the assumption is wrong (at least not without violating the
guarantees that @safe is supposed to provide). Since if the assumption turns
out to be wrong (which is quite possible, even if it's not likely in
well-tested code), then @safe would then violate memory safety.

As I understand it, by definition, @safe code is supposed to not have
undefined behavior in it, and certainly, if any compiler's optimizer takes
undefined behavior as meaning that it can do whatever it wants at that point
with no restrictions (which is what I gathered from our discussion at
dconf), then I don't see how any D compiler's optimizer can be allowed to
think that anything is UB in @safe code. That may be why Walter was updating
various parts of the spec a while back to talk about compiler-defined as
opposed to undefined, since there are certainly areas where the compiler can
have leeway with what it does, but there are places (at least in @safe
code), where there must be restrictions on what it can assume and do even
when the implementation is given leeway, or @safe's memory safety guarantees
won't actually be properly guaranteed.

In any case, clearly this needs to be sorted out with Walter, and the D spec
needs to be updated in whatever manner best fixes the problem. Null pointers
/ references need to be guaranteed to be @safe in @safe code. Whether that's
going to require that the compiler insert additional null checks in at least
some places, I don't know. I simply don't know enough about how things work
with stuff like the optimizers, but it wouldn't surprise me if in at least
some cases, the compiler is ultimately going to be forced to insert null
checks. Certainly, at minimum, I think that it's quite clear that if a
platform doesn't 

Re: Why does nobody seem to think that `null` is a serious problem in D?

2018-11-20 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, November 20, 2018 11:04:08 AM MST Johan Engelen via Digitalmars-
d-learn wrote:
> On Tuesday, 20 November 2018 at 03:38:14 UTC, Jonathan M Davis
>
> wrote:
> > For @safe to function properly, dereferencing null _must_ be
> > guaranteed to be memory safe, and for dmd it is, since it will
> > always segfault. Unfortunately, as understand it, it is
> > currently possible with ldc's optimizer to run into trouble,
> > since it'll do things like see that something must be null and
> > therefore assume that it must never be dereferenced, since it
> > would clearly be wrong to dereference it. And then when the
> > code hits a point where it _does_ try to dereference it, you
> > get undefined behavior. It's something that needs to be fixed
> > in ldc, but based on discussions I had with Johan at dconf this
> > year about the issue, I suspect that the spec is going to have
> > to be updated to be very clear on how dereferencing null has to
> > be handled before the ldc guys do anything about it. As long as
> > the optimizer doesn't get involved everything is fine, but as
> > great as optimizers can be at making code faster, they aren't
> > really written with stuff like @safe in mind.
>
> One big problem is the way people talk and write about this
> issue. There is a difference between "dereferencing" in the
> language, and reading from a memory address by the CPU.
> Confusing language semantics with what the CPU is doing happens
> often in the D community and is not helping these debates.
>
> D is proclaiming that dereferencing `null` must segfault but that
> is not implemented by any of the compilers. It would require
> inserting null checks upon every dereference. (This may not be as
> slow as you may think, but it would probably not make code run
> faster.)
>
> An example:
> ```
> class A {
>  int i;
>  final void foo() {
>   import std.stdio; writeln(__LINE__);
>  // i = 5;
>  }
> }
>
> void main() {
>  A a;
>  a.foo();
> }
> ```
>
> In this case, the actual null dereference happens on the last
> line of main. The program runs fine however since dlang 2.077.
> Now when `foo` is modified such that it writes to member field
> `i`, the program does segfault (writes to address 0).
> D does not make dereferencing on class objects explicit, which
> makes it harder to see where the dereference is happening.

Yeah. It's one of those areas where the spec will need to be clear. Like
C++, D doesn't actually dereference unless it needs to. And IMHO, that's
fine. The core issue is that operations that aren't memory safe can't be
allowed to happen in @safe code, and the spec needs to be defined in such a
way that requires that that be true, though not necessarily by being super
specific about every detail about how a compiler is required to do it.

> So, I think all compiler implementations are not spec compliant
> on this point.
> I think most people believe that compliance is too costly for the
> kind of software one wants to write in D; the issue is similar to
> array bounds checking that people explicitly disable or work
> around.
> For compliance we would need to change the compiler to emit null
> checks on all @safe dereferences (the opposite direction was
> chosen in 2.077). It'd be interesting to do the experiment.

Ultimately here, the key thing is that it must be guaranteed that
dereferencing null is @safe in @safe code (regardless of whether that
involves * or . and regardless of how that is achieved). It must never read
from or write to invalid memory. If it can, then dereferencing a null
pointer or class reference is not memory safe, and since there's no way to
know whether a pointer or class reference is null or not via the type
system, dereferencing pointers and references in general would then be
@system, and that simply can't be the case, or @safe is completely broken.

Typically, that protection is done right now via segfaults, but we know that
that's not always possible. For instance, if the object is large enough
(larger than one page size IIRC), then attempting to dereference a null
pointer won't necessarily segfault. It can actually end up accessing invalid
memory if you try to access a member variable that's deep enough in the
object. I know that in that particular case, Walter's answer to the problem
is that such objects should be illegal in @safe code, but AFAIK, neither the
compiler nor the spec have yet been updated to match that decision, which
needs to be fixed. But regardless, in any and all cases where we determine
that a segfault won't necessarily protect against accessing invalid memory
when a null pointer or reference is dereferenced, then we need to do
_something_ to guarantee that that code is @safe - which probably means
adding additional null checks in most cases, though in the case of the
overly large object, Walter has a different solution.

IMHO, requiring something in the spec like "it must segfault when
dereferencing null" as has been 

Re: Why does nobody seem to think that `null` is a serious problem in D?

2018-11-20 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, November 20, 2018 8:38:40 AM MST Kagamin via Digitalmars-d-learn 
wrote:
> On Monday, 19 November 2018 at 21:23:31 UTC, Jordi Gutiérrez
>
> Hermoso wrote:
> > When I was first playing with D, I managed to create a segfault
> > by doing `SomeClass c;` and then trying do something with the
> > object I thought I had default-created, by analogy with C++
> > syntax.
>
> D is more similar to Java here and works like languages with
> reference types - Java, C#, Python, Ruby, JavaScript. Also AFAIK
> in C++ objects are garbage-created by default, so you would have
> a similar problem there. To diagnose crashes on linux you can run
> your program under gdb.

In C++, if the class is put directly on the stack, then you get a similar
situation to D's structs, only instead of it being default-initialized, it's
default-constructed. So, you don't normally get garbage when you just
declare a variable of a class type (though you do with other types, and
IIRC, if a class doesn't have a user-defined default constructor, and a
member variable's type doesn't have a default constructor, then that member
variable does end up being garbage).

However, if you declare a pointer to a class (which is really more analagous
to what you're doing when declaring a class reference in D), then it's most
definitely garbage, and the behavior is usually _far_ worse than
segfaulting. So, while I can see someone getting annoyed about a segfault,
because they forgot to initialize a class reference in D, the end result is
far, far safer than what C++ does. And in most cases, you catch the bug
pretty fast, because pretty much the only way that you don't catch it is if
that piece of code is never tested. So, while D's approach is by no means
perfect, I don't think that there's really any question that as far as
memory safety goes, it's far superior to C++.

- Jonathan M Davis






Re: Why does nobody seem to think that `null` is a serious problem in D?

2018-11-19 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, November 19, 2018 5:30:00 PM MST Steven Schveighoffer via 
Digitalmars-d-learn wrote:
> On 11/19/18 7:21 PM, Jordi Gutiérrez Hermoso wrote:
> > On Monday, 19 November 2018 at 21:52:47 UTC, Steven Schveighoffer wrote:
> >> A null pointer dereference is an immediate error, and it's also a safe
> >> error. It does not cause corruption, and it is free (the MMU is doing
> >> it for you).
> >
> > Is this always true for all arches that D can compile to? I remember
> > back in the DOS days with no memory protection you really could read OS
> > data around the beginning.
>
> It's true for all OSes that D supports, and for most modern operating
> systems, that run in protected mode.
>
> It would NOT necessarily be true for kernel modules or an OS kernel, so
> that is something to be concerned about.

For @safe to function properly, dereferencing null _must_ be guaranteed to
be memory safe, and for dmd it is, since it will always segfault.
Unfortunately, as understand it, it is currently possible with ldc's
optimizer to run into trouble, since it'll do things like see that something
must be null and therefore assume that it must never be dereferenced, since
it would clearly be wrong to dereference it. And then when the code hits a
point where it _does_ try to dereference it, you get undefined behavior.
It's something that needs to be fixed in ldc, but based on discussions I had
with Johan at dconf this year about the issue, I suspect that the spec is
going to have to be updated to be very clear on how dereferencing null has
to be handled before the ldc guys do anything about it. As long as the
optimizer doesn't get involved everything is fine, but as great as
optimizers can be at making code faster, they aren't really written with
stuff like @safe in mind.

> >> Consistent segfaults are generally easy to figure out.
> >
> > I think I would still prefer a stack trace like other kinds of D errors.
> > Is this too difficult?
>
> Yes and no. It's good to remember that this is a HARDWARE generated
> exception, and each OS handles it differently. It's also important to
> remember that a segmentation fault is NOT necessarily the result of a
> simple error like forgetting to initialize a variable. It could be a
> serious memory corruption error. Generating stack traces can be
> dangerous in this kind of state.
>
> As I said, on Linux you can enable a "hack" that generates an error for
> a null dereference. On Windows, I believe that it already generates an
> exception without any modification.
>
> On other OSes you may be out of luck until someone figures out a nice
> clever hack for it.
>
> And if it's repeatable, you can always run in a debugger to see where
> the error is occurring.

Also, if your OS supports core dumps, and you have them turned on, then it's
trivial to get a stack trace - as well as a lot more of the program state.

- Jonathan M Davis






Re: opDispatch doesn't play nice with inheritance

2018-11-18 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, November 17, 2018 11:09:51 PM MST Carl Sturtivant via 
Digitalmars-d-learn wrote:
> On Thursday, 15 November 2018 at 19:01:45 UTC, Ali Çehreli wrote:
> > On 11/15/2018 09:14 AM, Carl Sturtivant wrote:
> > > opDispatch is special in that it allows for functions to be
> >
> > added to a
> >
> > > class or struct when undefined overtly but used elsewhere but
> >
> > it seems
> >
> > > those functions sadly are final.
> > >
> > > Can anything useful be done to remedy the situation?
> >
> > For the compiler to be able to make all opDispatch
> > instantiations virtual, it would have to first see all calls
> > that generate opDispatch instantiations. (Impossible in the
> > presence of separate compilation.)
> >
> > Only then the compiler would know how large the vtbl of the
> > base class should be and what member functions of the derived
> > class are overrides of those virtual functions.
>
> I suppose it's such administrative difficulties that led to D
> defining anything that might conceivably be overridden to be
> virtual, whether or not actually overridden.

The issue with templated functions is that you don't have the full list of
instantiations when the base class is compiled, whereas as I understand it,
the issue with virtual-by-default is more of an issue of choosing code
correctness by default over efficiency by default.

You can get some fun, subtle bugs in C++ when you call non-virtual functions
in circumstances where they were overridden and used as if they were
virtual. So, by making all public and protected class member functions
virtual by default and not allowing non-virtual functions to be overridden,
it prevents a whole class of bugs. It _does_ have some performance downsides
in that it easily leads to functions being virtual when they don't need to
be, which can be gotten around with some extra effort, but it's effectively
favoring correctness by default over efficiency. And for a lot of programs,
it's a great tradeoff, especially when the whole point of classes in D is to
use inheritance and polymorphism, and the cases where you don't need it, you
use a struct. For the rest, final can be used to devirtualize a function as
long as it's not overriding a function.

To avoid bugs in the same way that we currently do without having virtual be
the default, we probably would have had to make it illegal to override any
class functions unless they were explicitly virtual, which would have
created a different set of problems. And whether that would be better or
worse is a matter of debate. In the end, it's a matter of tradeoffs, and
which is better is likely to depend on how your applications benefit from
and use the feature. If most of your class functions are used
polymorphically, then having to mark them as virtual or having to put
virtual: at the top of your class would get really annoying, whereas if you
typically have only a few virtual functions and then lots of non-virtual
property functions (like the AAA guys apparently like to do), then having to
mark things with final to devirtualize them is very annoying. There's no
pleasing everyone. Either way, allowing overriding non-virtual functions
like C++ does would just be begging for bugs.

- Jonathan M Davis






Re: Problem with opBinary

2018-11-14 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, November 14, 2018 2:54:27 AM MST realhet via Digitalmars-d-
learn wrote:
> Hi,
>
> Just a little weird thing I noticed and don't know why it is:
>
> I have a FilePath struct and I wanted to make it work with the
> "~" operator and an additional string.
>
> So I've created a global funct:
>
>FilePath opBinary(string op:"~")(FilePath p1, string p2){
>  return FilePath(p1, p2);
>}
>
> The problem is that this funct is only callable with the
> following code:
>
>auto vlcPath = programFilesPath.opBinary!"~"(`VideoLAN\VLC`);
>
> And it is not callable using the ~ operator directly. It says
> unable to call with types  FilePath and string
>
> When I rewrite the opBinary funct as a member of the FilePath
> struct, everything is working fine. The problem is only happening
> when opBinary is a global funct. (I'm using LDC Win64)
>
> Is it a bug or is there an explanation to this?

In D, all overloaded operators must be member functions.

- Jonathan M Davis





Re: Why is stdio ... stdio?

2018-11-10 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, November 10, 2018 7:51:36 PM MST Adam D. Ruppe via Digitalmars-
d-learn wrote:
> On Saturday, 10 November 2018 at 23:29:12 UTC, Jonathan M Davis
>
> wrote:
> > The fact that they got added to ddoc just further degrades it
> > as a proper, macro-based markup language.
>
> The backticks were added to ddoc because they enabled something
> that was *virtually impossible* in ddoc before - proper character
> escaping. It actually originally had nothing to do with syntax
> sugar nor even with presentation - just the constant repetition
> of that myth has made it into a bit of reality.

It may be that a feature was needed to do better character escaping, but
backticks really don't fit in with ddoc as a whole, and they've only
encouraged folks to try and add further markdown features to ddoc, which
IMHO, is incredibly negative. On the whole, the worst features of ddoc are
the ones that act least like macros. They're the ones that are most
"magical" and the ones that generally have to be fought and worked around.
Adding more markdown features just makes things worse. As such, I very much
wish that we'd found a different way to fix the character escaping problem.

Regardless, none of that has anything to do with what we do with syntax
highlighting in the newsgroup's web interface.

> On the forum though, characters are already escaped properly, so
> there's no need here. Syntax highlighting for larger blocks is
> something I'm meh on - I don't really care either way if we
> wanted to do it.

I don't really care what the web interface tries to highlight, but I don't
want it doing anything that encourages people to start putting markdown in
their messages, because I don't use the web interface, I don't want to have
to see markdown in the middle of plain text messages any more than I want to
see html.

- Jonathan M Davis





Re: Why is stdio ... stdio?

2018-11-10 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, November 10, 2018 6:53:14 AM MST Kagamin via Digitalmars-d-
learn wrote:
> On Friday, 9 November 2018 at 09:11:37 UTC, Jonathan M Davis
>
> wrote:
> > No, I didn't. I just used underscores, which has been used with
> > plain text for emphasis for decades. Supporting markdown, would
> > involve stuff like backticks for code highlighting

Backticks are not from ddoc. They're from markdown and only got added to
ddoc later. The fact that they got added to ddoc just further degrades it as
a proper, macro-based markup language. Regardless, if it isn't clear that
something is code, just put it on its own line, just like folks have been
doing in mailing lists and newsgroups for decades.

- Jonathan M Davis





Re: Using decodeFront with a generalised input range

2018-11-09 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, November 9, 2018 5:22:27 AM MST Vinay Sajip via Digitalmars-d-
learn wrote:
> On Friday, 9 November 2018 at 11:24:42 UTC, Jonathan M Davis
>
> wrote:
> > decode and decodeFront are for converting a UTF code unit to a
> > Unicode code point. So, you're taking UTF-8 code unit (char),
> > UTF-16 code unit (wchar), or a UTF-32 code unit (dchar) and
> > decoding it. In the case of UTF-32, that's a no-op, since
> > UTF-32 code units are already code points, but for UTF-8 and
> > UTF-16, they're not the same at all.
> >
> > I would advise against doing much with decode or decodeFront
> > without having a decent understanding of the basics of Unicode.
>
> I think I understand enough of the basics of Unicode, at least
> for my application; my unfamiliarity is with the D language and
> standard library, to which I am very new.
>
> There are applications where one needs to decode a stream of
> bytes into Unicode text: perhaps it's just semantic quibbling
> distinguishing between "a ubyte" and "a UTF-8 code unit", as
> they're the same at the level of bits and bytes (as I understand
> it - please tell me if you think otherwise). If I open a file
> using mode "rb", I get a sequence of bytes, which may contain
> structured binary data, parts of which are to be interpreted as
> text encoded in UTF-8. Is there something in the D standard
> library which enables incremental decoding of such (parts of) a
> byte stream? Or does one have to resort to the `map!(x =>
> cast(char) x)` method for this?

In principle, a char is assumed to be a UTF-8 code unit, though it's
certainly possible for code to manage to end up with a char that's not a
valid UTF-8 code unit. So, char is specifically a character type, whereas
byte and ubyte are 8 bit integer types which can contain arbitrary data. D
purposefully has char, wchar, and dchar as separate types from byte, ubyte,
short, ushort, etc. in order to distinguish between character types and
integer types, and in general, the D standard library does not treat byte or
ubyte as having anything to do with characters.

decode and decodeFront operate on ranges of characters, not ranges of
arbitrary integer types. So, if you have a range of byte or ubyte which
contains UTF-8 code units, and you want to use decode or decodeFront, then
you will need to convert that range to a range of char. map would likely be
the most straightforward way to do that.

- Jonathan M Davis





Re: Using decodeFront with a generalised input range

2018-11-09 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, November 9, 2018 3:45:49 AM MST Vinay Sajip via Digitalmars-d-
learn wrote:
> On Friday, 9 November 2018 at 10:26:46 UTC, Dennis wrote:
> > On Friday, 9 November 2018 at 09:47:32 UTC, Vinay Sajip wrote:
> >> std.utf.decodeFront(Flag useReplacementDchar =
> >> No.useReplacementDchar, S)(ref S str) if (isInputRange!S &&
> >> isSomeChar!(ElementType!S))
> >
> > This is the overload you want, let's check if it matches:
> > ref S str - your InputRange can be passed by reference, but you
> > specified S = dchar. S here is the type of the inputRange, and
> > it is not of type dchar. It's best not to specify S so the
> > compiler will infer it, range types can be very complicated.
> > Once we fix that, let's look at the rest:
> >
> > isInputRange!S - S is an inputRange
> > isSomeChar!(ElementType!S) - ElementType!S is ubyte, but
> > isSomeChar!ubyte is not true.
> >
> > The function wants characters, but you give bytes. A quick fix
> > would be to do:
> > ```
> > import std.algorithm: map;
> > auto mapped = r.map!(x => cast(char) x);
> > mapped.decodeFront!(No.useReplacementDchar)();
> > ```
> >
> > But it may be better for somefn to accept an InputRange!(char)
> > instead.
> >
> > Note that if you directly do:
> > ```
> > r.map!(x => cast(char)
> > x).decodeFront!(No.useReplacementDchar)();
> > ```
> > It still won't work, since it wants `ref S str` and r.map!(...)
> > is a temporary that can't be passed by reference.
> >
> > As you can see, ensuring template constraints can be really
> > difficult. The error messages give little help here, so you
> > have to manually check whether the conditions of the overload
> > you want hold.
>
> Thanks, that's helpful. My confusion seems due to my thinking
> that a decoding operation converts (unsigned) bytes to chars,
> which is not how the writers of std.utf seem to have thought of
> it. As I see it, a ubyte 0x20 could be decoded to an ASCII char '
> ', and likewise to wchar or dchar. It doesn't (to me) make sense
> to decode a char to a wchar or dchar. Anyway, you've shown me how
> decodeFront can be used, so great!

decode and decodeFront are for converting a UTF code unit to a Unicode code
point. So, you're taking UTF-8 code unit (char), UTF-16 code unit (wchar),
or a UTF-32 code unit (dchar) and decoding it. In the case of UTF-32, that's
a no-op, since UTF-32 code units are already code points, but for UTF-8 and
UTF-16, they're not the same at all.

For UTF-8, a code point is encoded as 1 to 4 code units which are 8 bits in
size (char). For UTF-16, a code point is encoded as 1 or 2 code units which
are 16 bits in size (wchar), and for UTF-32, code points are encoded as code
units which are 32-bits in size (dchar). The decoding is doing that
conversion. None of this has anything to do with ASCII or any other encoding
except insofar as ASCII happens to line up with Unicode.

Code points are then 32-bit integer values (which D represents as dchar).
They are often called Unicode characters, and can be represented
graphically, but many of them represent bits of what you would actually
consider to be a character (e.g. an accent could be a code point on its
own), so in many cases, code points have to be combine to create what's
called a grapheme or grapheme cluster (which unfortunately, means that can
can have to worry about normalizing code points). std.uni provides code for
worrying about that sort of thing. Ultimately, what gets rendered to the
screen by with a font is as grapheme. In the simplest case, with an ASCII
character, a single character is a single code unit, a single code point,
and a single grapheme in all representations, but with more complex
characters (e.g. a Hebrew character or a character with a couple of accents
on it), it could be several code units, one or more code points, and a
single grapheme.

I would advise against doing much with decode or decodeFront without having
a decent understanding of the basics of Unicode.

> Supplementary question: is an operation like r.map!(x =>
> cast(char) x) effectively a run-time no-op and just to keep the
> compiler happy, or does it actually result in code being
> executed? I came across a similar issue with ranges recently
> where the answer was to map immutable(byte) to byte in the same
> way.

That would depend on the optimization flags chosen and the exact code in
question. In general, ldc is more likely to do a good job at optimizing such
code than dmd, though dmd doesn't necessarily do a bad job. I don't know how
good a job dmd does in this particular case. It depends on the code. In
general, dmd compiles very quickly and as such is great for development,
whereas ldc does a better job at generating fast executables. I would expect
ldc to optimize such code properly.

- Jonathan M Davis





Re: Why is stdio ... stdio?

2018-11-09 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, November 9, 2018 1:27:44 AM MST Kagamin via Digitalmars-d-learn 
wrote:
> On Friday, 9 November 2018 at 06:42:37 UTC, Jonathan M Davis
>
> wrote:
> > Honestly, having markdown in messages being typical would be
> > _really_ annoying for those of us not using the web interface,
> > because we'd see all of those backticks and the like as
> > backticks, not as syntax highlighting. It would be like seeing
> > html, albeit far less intrusive. I for one would much rather
> > that things just stay as pure text and that we not be adding
> > any features to the web interface that encourages adding _any_
> > kind of markup to messages. The web interface makes it easier
> > for folks who don't want to use a newsgroup or mailing list to
> > interact with the newsgroup, but it's still a newsgroup, and
> > _many_ of us use it as such.
>
> You used markdown three times in your message.

No, I didn't. I just used underscores, which has been used with plain text
for emphasis for decades. Supporting markdown, would involve stuff like
backticks for code highlighting, and special markup for urls - stuff that
doesn't actually provide information to someone who's reading plain text but
just gets in the way, whereas the underscores _do_ provide information to
someone reading plain text.

- Jonathan M Davis





Re: Why is stdio ... stdio?

2018-11-08 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, November 8, 2018 7:25:45 PM MST Neia Neutuladh via Digitalmars-
d-learn wrote:
> It's not a forum. It's a newsgroup that happens to have a web interface.
> Newsgroups are text-only. So bbcode is out, html is out, but interpreting
> markdown might be reasonable. But nobody's done that work.

Honestly, having markdown in messages being typical would be _really_
annoying for those of us not using the web interface, because we'd see all
of those backticks and the like as backticks, not as syntax highlighting. It
would be like seeing html, albeit far less intrusive. I for one would much
rather that things just stay as pure text and that we not be adding any
features to the web interface that encourages adding _any_ kind of markup to
messages. The web interface makes it easier for folks who don't want to use
a newsgroup or mailing list to interact with the newsgroup, but it's still a
newsgroup, and _many_ of us use it as such.

- Jonathan M Davis





Re: Exception slipping through the catch block?

2018-11-08 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, November 8, 2018 2:34:38 PM MST H. S. Teoh via Digitalmars-d-
learn wrote:
> On Thu, Nov 08, 2018 at 01:28:47PM -0700, Jonathan M Davis via 
Digitalmars-d-learn wrote:
> > On Thursday, November 8, 2018 10:55:45 AM MST Stanislav Blinov via
> >
> > Digitalmars-d-learn wrote:
> > > On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote:
> [...]
>
> > > > No, you should never catch Errors. They're separate for a
> > > > reason.
> > >
> > > Never say never :) There are legitimate cases for catching an
> > > Error or even a Throwable (for example, error propagation in a
> > > multi-threaded environment). However, this is not one of such
> > > cases.
> >
> > Yeah, but basically, the rule of thumb is never. Errors are fatal
> > error conditions which are supposed to terminate the program, and
> > programs should not be trying to recover from them. No one should be
> > attempting to catch them unless they know what they're doing, which
> > honestly, probably isn't going to be very many people for something
> > like this.
>
> Recently I ran into a case where catching Throwable makes sense: I have
> an Android application where the main code interfacing with the Android
> OS is written in Java, but program logic is written in D, called via
> JNI.  Since the JVM obviously cannot handle D exceptions, any unhandled
> D exception that makes it past the JNI boundary would cause the
> application to crash.  So what I did was to have the JNI interfacing
> code (on the D side) catch *everything*, i.e., Throwable, marshall the
> error message into a Java object, then send it via JNI back to the Java
> code that then displays the error message before aborting the
> application.  Extremely valuable in debugging, since otherwise I'd have
> to extract the stacktrace from the system logs, which is a pain.

You ran into one of the rare cases where it makes sense catch an Error or a
Throwable, and you're one of the few people who understands the situation
well enough to deal with it properly. The vast majority of D programmers
don't. Certainly, anyone who has to ask about the differences between
Throwable, Error, and Exception doesn't.

- Jonathan M Davis





Re: Exception slipping through the catch block?

2018-11-08 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, November 8, 2018 10:55:45 AM MST Stanislav Blinov via 
Digitalmars-d-learn wrote:
> On Thursday, 8 November 2018 at 16:13:55 UTC, Mike Parker wrote:
> > On Thursday, 8 November 2018 at 15:50:38 UTC, helxi wrote:
> >> Although it's pretty frustrating, isn't it? Now not only I
> >> have to think about catching exceptions but also about Errors,
> >> and have no guarantee that I have everything under control.
> >
> > No, you should never catch Errors. They're separate for a
> > reason.
>
> Never say never :) There are legitimate cases for catching an
> Error or even a Throwable (for example, error propagation in a
> multi-threaded environment). However, this is not one of such
> cases.

Yeah, but basically, the rule of thumb is never. Errors are fatal error
conditions which are supposed to terminate the program, and programs should
not be trying to recover from them. No one should be attempting to catch
them unless they know what they're doing, which honestly, probably isn't
going to be very many people for something like this.

Exceptions are for error conditions which are potentially recoverable.
Program input or environmental state was bad (e.g. a missing file). They
aren't necessarily indicative of bugs in the program, and the program can
potentially recover from them and continue to function perfectly fine.

Errors on the other hand, are used to indicate actual bugs in the program or
fatal conditions with resources which cannot be recovered from (e.g. the GC
running out of memory). They are intended simply to be informative and not
to be caught. The stack is not necessarily properly unwound when they are
thrown. Full exception handling code is not necessarily even in place when
they are thrown, and they can be thrown from nothrow code. By definition,
your program is in an invalid state when you catch an Error, and catching an
Error to do much of anything is dangerous.

> helxi, an AssertError means there's a problem with your code, it
> needs to be dealt with by fixing the code, not swallowing the
> Error.

Specifically, AssertError means that either an assertion failed or something
simulating an assertion failed (such as std.exception.assertThrown), so it's
something in the code that quite specifically indicates that there's a bug
in the code and that a condition that must be true for the code to be in a
valid state was false. So, whatever it reported should be tracked down and
fixed. In this particular case, it looks like a piece of code called
dropBackOne on an empty range.

- Jonathan M Davis





Re: Is this a bug? +goto

2018-11-08 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, November 8, 2018 2:34:34 AM MST Michelle Long via Digitalmars-
d-learn wrote:
> Obviously, but that is not the case I mentioned. You can assume
> that I know how scopes work. No need to assume everyone that
> shows two cases that you have to bring up an unrelated case as a
> potential cause unless it is relevant.
>
> Remember, I'm showing the starting case that has the bug and the
> final case that doesn't... it is simply "mental dustmite" on the
> code I have.
>
> You shouldn't assume everyone can't comprehend such trivialities.
>
> If a person cannot understand scope then I doubt they understand
> goto's... and definitely not that adding braces should not change
> the compiler behavior.
>
> What happens when you do that you just create noise that makes it
> more difficult to have a proper discussion that gets at the whole
> point of the conversation.
>
> You seem to default to assuming that the person you are talking
> to has no clue about the problem at hand. You might not do it
> intentionally but it is wrong to assume that because it almost
> never helps.

If you fully understood the situation, you wouldn't be asking whether your
case was a compiler bug or not, and I don't know which parts you do and
don't understand. So, I tried to be thorough in explaining the situation.
And yes, by being thorough, I'm more likely to cover information that you
already know and understand, but I'm also more likely to cover the
information that you actually need. In order to avoid repeating anything you
already understand and only tell you exactly what you need to know, I would
have to somehow understand exactly which piece of the puzzle it is you're
missing, and I don't.

Honestly, that rarely seems to be easy to do, and for whatever reason, it
seems to be even harder to do than normal when discussing this issue with
you. It seems like most of the discussion of this issue between you and
various folks has been people talking passed each other without really
coming to an understanding, which always makes for a frustrating discussion.

I'd like to help, but I don't know what else I can say. I've tried to
explain how braces interact with goto and why, so you should be able to
figure out whether you're dealing with a compiler bug or not. And if you
are, unless you're dealing with one that someone else already has found
independently and reported with a test case, somehow, you're going to need
to reduce it enough to be able to create a bug report with an example if you
want it fixed. A small example would be nice, but even a large example would
be better than nothing. Either way, ultimately, without a reproducible test
case, compiler bugs almost never get fixed. It just isn't practical for the
compiler devs to track down bugs based on vague bug reports, even if they'd
like to be helpful.

- Jonathan M Davis





Re: is opOpAssign returning a value less than ideal ?

2018-11-08 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, November 8, 2018 2:15:43 AM MST Codifies via Digitalmars-d-learn 
wrote:
> On Thursday, 8 November 2018 at 06:01:57 UTC, Jonathan M Davis
>
> wrote:
> > On Wednesday, November 7, 2018 10:45:07 PM MST Jonathan M Davis
> >
> > via Digitalmars-d-learn wrote:
> >> [...]
> >
> > Rereading what you wrote, are you asking whether it's
> > reasonable to return a value instead of a reference?
> > Personally, I don't think that that's good design at all, but I
> > also don't see any reason for the compiler to prevent it.
> >
> > Personally, I think that the default design should be to return
> > by ref. Returning void is less than ideal but isn't necessarily
> > bad, depending on the situation (especially if we're not
> > talking about a general purpose library). However, I expect
> > that returning non-void by value rather than by ref is rarely
> > -if ever - going to be a good design choice. It's just going to
> > be confusing and not particularly useful.
> >
> > - Jonathan M Davis
>
> NB its not returning a ref to the list, its returning the newly
> created node when you use the operator you add a type to the
> list, so it possibly wouldn't be that much use for chaining?

The normal thing to do with any of the assignment operators is to return a
reference to the object you're assigning to. Doing much of anything else
other than returning void (and thus not allowing chaining) would be pretty
abnormal. If it's appropriately documented, having an assignment operator
return something else could certainly be made to work, but I expect that
most programmers would consider it to be a backwards API.

- Jonathan M Davis





Re: Is this a bug? +goto

2018-11-07 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, November 7, 2018 10:50:29 PM MST Michelle Long via 
Digitalmars-d-learn wrote:
> On Thursday, 8 November 2018 at 02:22:42 UTC, Jonathan M Davis
>
> wrote:
> > On Wednesday, November 7, 2018 1:03:47 PM MST Michelle Long via
> >
> > Digitalmars- d-learn wrote:
> >> Don't let their psychobabble fool you. They are wrong and you
> >> were right from the start.
> >
> > ...
> >
> >> Case A:
> >> {
> >>
> >> if (true) goto X;
> >> int x;
> >>
> >> }
> >> X:
> >>
> >>
> >> Case B:
> >> {
> >>
> >> if (true) goto X;
> >> {
> >>
> >>int x;
> >>
> >> }
> >>
> >> }
> >> X:
> >>
> >>
> >> These two cases are EXACTLY the same semantically. It's like
> >> writing A + B and (A + B).
> >
> > That's not the situation that the OP was describing. If adding
> > braces in a situation where the braces have no semantic effect
> > has any impact on goto, then it's a compiler bug. It's adding a
> > new scope that affects the lifetime of a variable whose
> > declaration is being jumped over by a goto that matters.
> >
> > I know that you're frustrated, because you've hit a problem
> > with goto in complex code, and you don't have a simple example
> > that shows the compiler bug, but the approach that D takes with
> > goto (and any construct that potentially requires code flow
> > analysis) of avoiding requiring that the compiler be smart is
> > precisely to reduce the risk of there being cases where the
> > compiler is going to screw it up in complex code even though it
> > gets it right in the simple cases. If the language required the
> > compiler to be smart about such things, we'd have a lot more
> > problems with subtle, hard to track down compiler bugs in
> > complex code. So, we'd just have _more_ cases where people
> > would be hitting frustrating bugs like you are.
>
> That's fine. The D compiler writers can decide to do whatever
> they want. I can simply take my "business" elsewhere if I don't
> like it.
>
> What I am talking about is about an obvious error(Ok, I haven't
> produced a simplified test case but dustmite or visual D is not
> working for me to do so at this point in time, but it would be
> nice for sake of argument to assume I'm right...).
>
> > Regardless, if you want to actually have your problem fixed,
> > you're going to need to provide a reproducible test case in a
> > bugzilla report, even if it's large, otherwise no one is going
> > to be able to track it down for you.
>
> That's easier said than done. I wasn't expecting anyone to be
> able to fix a bug that can't be reproduced.
>
> What I expect is that, given my assumptions that I'm right, that
> people can agree the compiler does have a bug or flaw that can
> easily be fixed give then two simplified test cases basic purely
> what I have done in my own code.
>
> 1.
>
> foreach(...)
> {
>if (x) goto Y:
>int z;
> }
> Y:
>
> Fails.
>
> foreach(...)
> {
>if (x) goto Y:
>{
>   int z;
>}
> }
> Y:
>
> Passes.
>
> THAT IS FACT! It doesn't matter if the examples work above. I
> have simplified what I have done and in my code I simply add
> brackets and it works! That is what people should be thinking
> about... not test cases, MWE's, compiler versions, etc.
>
> Is it logical that the compiler **should** error out in the first
> case and no in the second?
>
> That is what the discussion is ALL about. Once that is dealt with
> then we can move on to finding out more specifics. There is no
> reason to build the windows of a house before the foundation,
> it's just far more work without any benefit.
>
>
> Once people can say: If that is all you are doing is adding
> brackets around what follows the goto and break out of
> scope(which is what the code above says) and you can compile,
> then it is a compiler bug or flaw.
>
> Once people verify that, rather than trying to create rabbit
> holes, then I can do more work on finding out more specifics.
> Until then, it is pointless to do anything on my side because if
> people come back and say "No, it is suppose to work that way"
> then what the hell am I trying to simplify and fix? It's not a
> bug then.

If you have code where you get a compiler error about a goto skipping the
initializiation of a variable, and you add braces that should have no
semantic effect on the code whatsoever, and the error goes away, then yes,
that's a compiler bug. If, however, the braces do affect the semantics of
the code, then that's not necessarily a compiler bug. At that point, whether
it's a compiler bug or not would depend on what exactly the code was.

In an example such as

while(1)
{
if(cond)
goto label;
int x;
}
label:

adding braces such as

while(1)
{
if(cond)
{
goto label;
}
int x;
}
label:

or

while(1)
{
if(cond)
goto label;
{
int x;
}
}
label:

should have no effect. However, in an example such as

goto label;
int x;
label:

adding braces such as

goto label;
{
int x;
}
label:

changes the 

Re: is opOpAssign returning a value less than ideal ?

2018-11-07 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, November 7, 2018 10:45:07 PM MST Jonathan M Davis via 
Digitalmars-d-learn wrote:
> On Wednesday, November 7, 2018 9:28:19 PM MST Codifies via Digitalmars-d-
>
> learn wrote:
> > I noticed that opOpAsign allows you to return a value...
> >
> > this means I can do this (return a node from my list class when
> > adding a new node)
> > ```
> > anode = alist ~= 
> > ```
> > to me this looks a little unusual (but to be fair I can live with
> > it)
> >
> > being as when its used like this:
> > ```
> > alist ~= 
> > ```
> > you need to find out what the ~ operator does anyway, I don't
> > think it harms readability
> >
> > any thoughts?
>
> It's common practice in C++ to have the various assignment operators
> return a reference to the object being assigned to so that the operations
> can be chained, and I don't see why the situation in D would be any
> different. But if for whatever reason, you don't want to do the same with
> your types, you can always just make those operators void. Either way,
> the fact that an assignment operator returns a reference to the object
> doesn't require you to then actually use it for anything. It just allows
> folks to do so if they think that it's appropriate in a particular piece
> of code. Sometimes, it's useful; often it isn't, but if the return type
> is void, then you can't do it even in the cases where it would be useful.

Rereading what you wrote, are you asking whether it's reasonable to return a
value instead of a reference? Personally, I don't think that that's good
design at all, but I also don't see any reason for the compiler to prevent
it.

Personally, I think that the default design should be to return by ref.
Returning void is less than ideal but isn't necessarily bad, depending on
the situation (especially if we're not talking about a general purpose
library). However, I expect that returning non-void by value rather than by
ref is rarely -if ever - going to be a good design choice. It's just going
to be confusing and not particularly useful.

- Jonathan M Davis





Re: is opOpAssign returning a value less than ideal ?

2018-11-07 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, November 7, 2018 9:28:19 PM MST Codifies via Digitalmars-d-
learn wrote:
> I noticed that opOpAsign allows you to return a value...
>
> this means I can do this (return a node from my list class when
> adding a new node)
> ```
> anode = alist ~= 
> ```
> to me this looks a little unusual (but to be fair I can live with
> it)
>
> being as when its used like this:
> ```
> alist ~= 
> ```
> you need to find out what the ~ operator does anyway, I don't
> think it harms readability
>
> any thoughts?

It's common practice in C++ to have the various assignment operators return
a reference to the object being assigned to so that the operations can be
chained, and I don't see why the situation in D would be any different. But
if for whatever reason, you don't want to do the same with your types, you
can always just make those operators void. Either way, the fact that an
assignment operator returns a reference to the object doesn't require you to
then actually use it for anything. It just allows folks to do so if they
think that it's appropriate in a particular piece of code. Sometimes, it's
useful; often it isn't, but if the return type is void, then you can't do it
even in the cases where it would be useful.

- Jonathan M Davis





Re: Is this a bug? +goto

2018-11-07 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, November 7, 2018 1:03:47 PM MST Michelle Long via Digitalmars-
d-learn wrote:
> Don't let their psychobabble fool you. They are wrong and you
> were right from the start.

...

> Case A:
> {
> if (true) goto X;
> int x;
> }
> X:
>
>
> Case B:
> {
> if (true) goto X;
> {
>int x;
> }
> }
> X:
>
>
> These two cases are EXACTLY the same semantically. It's like
> writing A + B and (A + B).

That's not the situation that the OP was describing. If adding braces in a
situation where the braces have no semantic effect has any impact on goto,
then it's a compiler bug. It's adding a new scope that affects the lifetime
of a variable whose declaration is being jumped over by a goto that matters.

I know that you're frustrated, because you've hit a problem with goto in
complex code, and you don't have a simple example that shows the compiler
bug, but the approach that D takes with goto (and any construct that
potentially requires code flow analysis) of avoiding requiring that the
compiler be smart is precisely to reduce the risk of there being cases where
the compiler is going to screw it up in complex code even though it gets it
right in the simple cases. If the language required the compiler to be smart
about such things, we'd have a lot more problems with subtle, hard to track
down compiler bugs in complex code. So, we'd just have _more_ cases where
people would be hitting frustrating bugs like you are.

Regardless, if you want to actually have your problem fixed, you're going to
need to provide a reproducible test case in a bugzilla report, even if it's
large, otherwise no one is going to be able to track it down for you.

Now, a goto-related regression has recently been reported for joiner:

https://issues.dlang.org/show_bug.cgi?id=19213

where some code worked with joiner in 2.081.2 but does not work with 2.082.0
or later, so you may want to test your code with an older compiler release
to see if you've hit a compiler regression. If so, that could be a starting
point for tracking down the problem.

- Jonathan M Davis





Re: Is this a bug? +goto

2018-11-05 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, November 5, 2018 7:55:46 PM MST MatheusBN via Digitalmars-d-learn 
wrote:
> On Tuesday, 6 November 2018 at 01:55:04 UTC, Jonathan M Davis
>
> wrote:
> >> And I found a bit strange that in such code, since "x" is
> >> never used, why it isn't skipped.
> >
> > It's skipped right over. The goto jumps out of the scope, and
> > the line with
> >
> > int x;
> >
> > is never run. In fact, if you compile with -w or -wi, the
> > compiler will give you a warning about unreachable code.
>
> That is exactly my point.
>
> Since "x" it's skipped and never used, it shouldn't just be a
> warning (unreachable code) instead of an error?
>
> I'm trying to understand why/when such code could give any
> problem.
>
> On the other hand if the code were:
>
> {
> goto Q:
> int x;
>
> Q:
> x = 10; // <- Now you are accessing an uninitialized variable.
> }
>
> Then I think an error would be ok.

D tries to _very_ little with code flow analysis, because once you start
having to do much with it, odds are that the compiler implementation is
going to get it wrong. As such, any feature that involves code flow analysis
in D tends to be _very_ simple. So, D avoids the issue here by saying that
you cannot skip the initialization of a variable with goto. The compiler is
not going to do the complicated logic of keeping track of where you access
the variable in relation to the goto. That's exactly the sort of thing that
might be obvious in the simple case but is highly likely to be buggy in more
complex code. Code such as

{
goto Q;
int x;
}
Q:

or

{
if(foo)
goto Q;
int x;
}
Q:


is fine, because the compiler can trivially see that it is impossible for x
to be used after it's been skipped, whereas with something like

goto Q;
int x;
Q:

the compiler has to do much more complicated analysis of what the code is
doing in order to determine that, and when the code isn't trivial, that can
get _really_ complicated.

You could argue that it would be nicer if the language required that the
compiler be smarter about it, but by having the compiler be stupid, it
reduces the risk of compiler bugs, and most people would consider code doing
much with gotos like this to be poor code anyway. Most of the cases where
goto is reasonable tend to be using goto from inside braces already, because
it tends to be used as a way to more efficiently exit deeply nested code.
And with D's labeled break and continue, the need for using goto outside of
switch statements also tends to be lower than it is in C/C++.

- Jonathan M Davis





Re: Is this a bug? +goto

2018-11-05 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, November 5, 2018 5:33:56 PM MST MatheusBN via Digitalmars-d-learn 
wrote:
> On Tuesday, 6 November 2018 at 00:14:26 UTC, Jonathan M Davis
>
> wrote:
> > On Monday, November 5, 2018 4:54:59 PM MST MatheusBN via
> >
> > Digitalmars-d-learn wrote:
> >> Hi,
> >>
> >> I posted this in another thread but without any response.
> >>
> >> This code:
> >>
> >> void main(){
> >>
> >>   goto Q;
> >>   int x;
> >>   Q:
> >>   writeln("a");
> >>
> >> }
> >>
> >> Gives me this error: "source_file.d(4): Error: goto skips
> >> declaration of variable source.main.x at source_file.d(5)"
> >>
> >>
> >> Now, if I add a pair of brackets:
> >>
> >> void main(){
> >>
> >>   {
> >>
> >>   goto Q;
> >>   int x;
> >>
> >>   }
> >>   Q:
> >>   writeln("a");
> >>
> >> }
> >>
> >> It works. So Is this a bug?
> >
> > All the spec says on the matter is that
> >
> > "It is illegal for a GotoStatement to be used to skip
> > initializations."
> >
> > https://dlang.org/spec/statement.html#goto-statement
> >
> > In the first case, x exists at the label Q, and its
> > initialization was skipped, so it's clearly illegal. However,
> > in the second case, because of the braces, x does _not_ exist
>
> Just to be clear, when you say "x exists at the label Q", you
> mean at the same scope, right?

The scope that x was at is over at the label Q. So, x doesn't exist at the
label Q. It has no address at that point. It's not on the stack. It doesn't
exist in any sense other than the fact that it happens to be in the source
code above it. In fact, the line with x never even ran, so x _never_
existed.

> That's interesting but a bit confusing isn't?

I don't see why.

{
goto Q;
int x;
}
Q:

is basically the same thing as

while(1)
{
break;
int x;
}

The same thing happens in both cases.

> And I found a bit strange that in such code, since "x" is never
> used, why it isn't skipped.

It's skipped right over. The goto jumps out of the scope, and the line with

int x;

is never run. In fact, if you compile with -w or -wi, the compiler will give
you a warning about unreachable code.

> I know it's another language but in C at least in GCC there is no
> error over such code, so that's my confusion.

C is a different language, and it's one that generally doesn't care much
about safety. It allows all kinds of horrible things that cause bugs. The
folks behind D (and the folks behind _most_ languages since C/C++) tend to
prefer a greater degree of safety than C provides.

- Jonathan M Davis





Re: Is this a bug? +goto

2018-11-05 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, November 5, 2018 4:54:59 PM MST MatheusBN via Digitalmars-d-learn 
wrote:
> Hi,
>
> I posted this in another thread but without any response.
>
> This code:
>
> void main(){
>   goto Q;
>   int x;
>   Q:
>   writeln("a");
> }
>
> Gives me this error: "source_file.d(4): Error: goto skips
> declaration of variable source.main.x at source_file.d(5)"
>
>
> Now, if I add a pair of brackets:
>
> void main(){
>   {
>   goto Q;
>   int x;
>   }
>   Q:
>   writeln("a");
> }
>
> It works. So Is this a bug?

All the spec says on the matter is that

"It is illegal for a GotoStatement to be used to skip initializations."

https://dlang.org/spec/statement.html#goto-statement

In the first case, x exists at the label Q, and its initialization was
skipped, so it's clearly illegal. However, in the second case, because of
the braces, x does _not_ exist at the label Q, so its initialization was not
skipped, so I don't see why it wouldn't be legal based on what the spec
says, and I don't see any reason to make it illegal. Conceptually, it's
doing exactly what you'd get with a break if the braces were for a loop.
However, it is true that the spec could (and probably should) be more
specific on the matter.

- Jonathan M Davis





Re: Why use while if only iterating once ?

2018-11-03 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, November 3, 2018 3:03:16 PM MDT Venkat via Digitalmars-d-learn 
wrote:
>  while (1)
>  {
>  FLAGS f;
>  switch (*p)
>  {
>  case 'U':
>  case 'u':
>  f = FLAGS.unsigned;
>  goto L1;
>  case 'l':
>  f = FLAGS.long_;
>  error("lower case integer suffix 'l' is not
> allowed. Please use 'L' instead");
>  goto L1;
>  case 'L':
>  f = FLAGS.long_;
>  L1:
>  p++;
>  if ((flags & f) && !err)
>  {
>  error("unrecognized token");
>  err = true;
>  }
>  flags = cast(FLAGS)(flags | f);
>  continue;
>  default:
>  break;
>  }
>  break;
> }
>
>
> The last break statement prevents the loop from returned for a
> second iteration. Then why use a while ?

There's a continue right above the default case. So, if the code hits that
point, it will loop back to the top.

- Jonathan M Davis





Re: anyway to set a const object after the fact?

2018-10-30 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, October 30, 2018 2:18:15 AM MDT Laurent Tréguier via 
Digitalmars-d-learn wrote:
> On Monday, 29 October 2018 at 21:50:32 UTC, aliak wrote:
> > Hi, so if you have this piece of code:
> >
> > struct C {
> >
> >   void f() {
> >
> > string[] others;
> > const string[] restArgs;
> > foreach (i, arg; args) {
> >
> >   if (isValidArg(arg)) {
> >
> > restArgs = args[i + 1 .. $];
> > break;
> >
> >   }
> >   others ~= arg;
> >
> > }
> > // "others" is a list of args before the valid arg is
> >
> > encountered
> >
> > // "restArgs" is a list that is the args after the valid arg
> >
> >   }
> >
> > }
> >
> > Is there anyway to set a const object after declaring it in the
> > above context?
> >
> > Cheers,
> > - Ali
>
> It looks like there is a Rebindable type for that in std.typecons
>
> : https://dlang.org/phobos/std_typecons.html#Rebindable

Rebindable is specifically intentended for class references, since D doesn't
really distinguish between the reference and what it's pointing to, making
it impossible to under normal circumstances to have a mutable reference to a
const object. On the other hand, you can easily have mutable arrays of const
objects. Using Rebindable is a really a hack (albeit a very necessary one
for some circumstances), and I would very much advise _against_ using it if
you don't need it. Historically, it tends to run into compiler bugs, because
it's trying to hack it's way around the type system, and if you're not
dealing with class references, there's probably a better way to handle the
problem.

- Jonathan M Davis






Re: how to make '==' safe for classes?

2018-10-28 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, October 28, 2018 12:56:10 PM MDT ikod via Digitalmars-d-learn 
wrote:
> On Sunday, 28 October 2018 at 18:00:06 UTC, Stanislav Blinov
>
> wrote:
> > On Sunday, 28 October 2018 at 12:38:12 UTC, ikod wrote:
> >> and object.opEquals(a,b) do not inherits safety from class C
> >> properties, and also I can't override it.
> >
> > Yep. Since Object is the base class and it defines opEquals as:
> object.opEquals(a,b) even is not a Object member function, it's
> free function.
>
> It looks a bit unnatural for me, but thanks for confirmation!

It may seem weird at first, but it actually solves several problems that you
get when simple calling a.obEquals(b) - the most obvious of which is that
a.opEquals(b) has to worry about null, which opEquals(a, b) solves for you,
but if you look at the implementation I posted elsewhere in the thread, it
solves some other problems as well. It's one of those places where D was
able to learn from problems that languages that came before it had.
Unfortunately, the attribute problem is _not_ one of those areas.

- Jonathan M Davis





Re: how to make '==' safe for classes?

2018-10-28 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, October 28, 2018 6:38:12 AM MDT ikod via Digitalmars-d-learn 
wrote:
> Hello
>
> How to make this code to compile? My goal is safe(not @trusted)
> longFunction().
>
>
> ---
> class C
> {
>  override bool opEquals(Object o) const @safe
>  {
>  return true;
>  }
> }
> bool longFunction(C a, C b) @safe
> {
>  return a==b;
> }
> void main()
> {
> }
> ---
>
>
> As far as I understand the problem is that AST for this code
> looks like
>
> ---
> import object;
> class C : Object
> {
>   override const @safe bool opEquals(Object o)
>   {
>   return true;
>   }
> }
> bool longFunction(C a, C b)
> {
>   return opEquals(a, b);
> }
> void main()
> {
>   return 0;
> }
> RTInfo!(C)
> {
>   enum typeof(null) RTInfo = null;
>
> }
> ---
>
> and object.opEquals(a,b) do not inherits safety from class C
> properties, and also I can't override it.
>
> Is there clean way to use '==' here, or I have to convert this to
> a.opEquals(b) for classes, leaving '==' for structs?
>
> Thanks!

Because Object predats @safe (and most attributes), it really isn't
compatible with them. In fact, it predates const (since it's basically the
same as it was in D1) and it's only possible to compare const class objects
because of a hack in the free function opEquals (which == lowers to) which
casts away const (meaning that if you're not careful, you can actually
violate the type system with == by mutating an object in a class' opEquals).
And because attributes are inherited, even if we were willing to break
existing code by changing the attributes on Object, there really isn't a
good way to fix the problem, because whatever set of attributes we picked
(for @safe, nothrow, const, etc.) would work for some programs but not
others. That's why at one point, it was decided that we would remove all of
the various member functions from Object. Given the templates in D, they
really aren't necessary like they are in languages like Java. As long as
stuff like the built in AA implementation is templated (which it
unfortunately is not right now), all of the appropriate information can be
inferred, and it's not necessary to have a root class object with member
functions like opEquals in order to use it in generic code.

https://issues.dlang.org/show_bug.cgi?id=9769
https://issues.dlang.org/show_bug.cgi?id=9770
https://issues.dlang.org/show_bug.cgi?id=9771
https://issues.dlang.org/show_bug.cgi?id=9772

However, while that decision was made some time ago, actually implementing
it isn't easy, and the necessary steps have never happened - to the point
that it doesn't seem very likely at this point. What seems far more likely
is a DIP that Andrei has proposed:

https://github.com/andralex/DIPs/blob/ProtoObject/DIPs/DIP.md

It will introduce ProtoObject as a new root object below Object which does
not have any member functions or an embedded monitor object (which is only
necessary if you actually have synchronized functions). Object would stay
the default base class (since code would break otherwise), and any code
using Object would unfortunately continue to have the same problems, but
classes that then explicitly derive from ProtoObject would be able to define
opEquals, opCmp, toString, etc. with the signatures that were appropriate to
the applications or libraries that they're in. Any classes derived from such
classes would then be stuck with those attributes just like we're stuck with
the attributes on Object right now, but those choices would then be per
object hierarchy rather than forced on everyone using the language. So, it
looks like that's probably going to be the ultimate fix for this problem,
but we don't really have an ETA at the moment.

So, unfortunately, for now, you're going to have to use @trusted with == on
classes, as stupid as that is, though as a workaround, you could always
create an @trusted wrapper function that just called ==. It would still be
annoying, but it would be cleanly restricted the @trusted bits.

- Jonathan M Davis





Re: how to make '==' safe for classes?

2018-10-28 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, October 28, 2018 12:17:41 PM MDT Neia Neutuladh via Digitalmars-
d-learn wrote:
> On Sun, 28 Oct 2018 18:00:06 +, Stanislav Blinov wrote:
> > On Sunday, 28 October 2018 at 12:38:12 UTC, ikod wrote:
> >> and object.opEquals(a,b) do not inherits safety from class C
> >> properties, and also I can't override it.
> >
> > Yep. Since Object is the base class and it defines opEquals as:
> > ```
> > bool opEquals(Object);
> > ```
> >
> > the compiler rewrites `a == b` as
> > `(cast(Object)a).opEquals(cast(Object)ob)`, i.e. it inserts a @system
> > call into your code.
>
> More pedantically, it rewrites it as:
>
>   (a is b) ||
>   (a !is null && (cast(Object)a).opEquals(cast(Object)b))
>
> An object might not be equal to itself via opEquals, but it will always
> compare equal to itself with ==.

Technically, it calls the free function opEquals in object.d, which does
more than that (including introduce a hack to work around the type system to
allow comparing const objects). Specifically, the current implementation is

bool opEquals(Object lhs, Object rhs)
{
// If aliased to the same object or both null => equal
if (lhs is rhs) return true;

// If either is null => non-equal
if (lhs is null || rhs is null) return false;

// If same exact type => one call to method opEquals
if (typeid(lhs) is typeid(rhs) ||
!__ctfe && typeid(lhs).opEquals(typeid(rhs)))
/* CTFE doesn't like typeid much. 'is' works, but opEquals 
doesn't
(issue 7147). But CTFE also guarantees that equal TypeInfos are
always identical. So, no opEquals needed during CTFE. */
{
return lhs.opEquals(rhs);
}

// General case => symmetric calls to method opEquals
return lhs.opEquals(rhs) && rhs.opEquals(lhs);
}

/
* Returns true if lhs and rhs are equal.
*/
bool opEquals(const Object lhs, const Object rhs)
{
// A hack for the moment.
return opEquals(cast()lhs, cast()rhs);
}

- Jonathan M Davis





Re: Error: non-shared method core.sync.condition.Condition.notify is not callable using a shared object

2018-10-18 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, October 18, 2018 4:50:18 AM MDT Paolo Invernizzi via 
Digitalmars-d-learn wrote:
> There's a rational behind the fact that there's not a 'shared'
> version of notify/wait method in Condition?
>
> Thanks,
> Paolo

The original author of the stuff in core.sync didn't want to update it for
shared when shared was first introduced, because he didn't think that it was
well enough defined yet (e.g. there was discussion over whether it should
have write barriers or not). Some work has been done to improve shared
support in there since then but not enough. shared _does_ still need need
some rough edges sorted out (it's supposed to guarantee that you can't do
any operations on it that isn't thread-safe, but while many operations are
illegal, some which should be aren't, and some of the finer details likely
need to be cleaner up). The basics of shared have been in place and working
fine for nearly a decade, but because we've been waiting for the finer
details to be finished, and it's never been a high enough priority for that
to happen, stuff like core.sync has suffered. It doesn't help that the vast
majority of D programs don't need to do much with shared, and those that D
use higher level mechanisms such as std.concurrency or use something like
the framework that vibe.d provides.

However, as annoying as it is, with some extra casting, the pieces of
core.sync that haven't been updated properly _can_ be used with shared.
shared in general requires unsafe casting and always will. There really
isn't any way around that, but the parts of core.sync that don't use shared
properly will require that much more of it, unfortunately.

There's no question though that the situation with core.sync needs to be
fixed. Some of it has been worked on, but nowhere near enough.

- Jonathan M Davis





Re: custom sorting of lists ?

2018-10-13 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, October 13, 2018 6:52:05 PM MDT Steven Schveighoffer via 
Digitalmars-d-learn wrote:
> You can't quick-sort a list. You can merge sort it, and it's O(nlgn).
>
> I'll work on getting a sort routine into Phobos for it, but I don't know
> what the appropriate location for it is, as a member or along-side
> std.algorithm.sort.

Unless there's something about the implementation that's tied to the list
itself, I would think that it would make more sense to make it a generic
algorithm, then it will work with any non-random-access range, and it avoids
needing to reimplement it for similar circumstances. IMHO, it really only
makes sense to tie it to the container if the implementation itself needs to
be for some reason.

- Jonathan M Davis





Re: Why are 2-D arrays reversed?

2018-10-10 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, October 10, 2018 4:26:40 PM MDT Chris Katko via Digitalmars-d-
learn wrote:
> On Wednesday, 10 October 2018 at 16:00:42 UTC, Steven
>
> Schveighoffer wrote:
> > On 10/10/18 9:22 AM, Chris Katko wrote:
> >> int[][] data =
> >>
> >>  [
> >>  [1, 0, 1, 0, 0],
> >>  [1, 0, 1, 0, 0],
> >>  [1, 0, 1, 1, 1],
> >>  [1, 0, 0, 1, 0],
> >>  [5, 1, 1, 1, 0]
> >>  ];
> >>
> >> when drawn with data[i][j], prints the transpose of "data":
> >>
> >> [1, 1, 1, 1, 5]
> >> [0, 0, 0, 0, 1]
> >> [1, 1, 1, 0, 1]
> >> [0, 0, 1, 1, 1]
> >> [0, 0, 1, 0, 0]
> >>
> >> So, if I flip [i][j] and print a row of "j's", it'll be
> >> correct. It's very confusing and counter-intuitive to have to
> >> remember to swap i and j every time I use an array.
> >>
> >> I guess when I load data from files, the i/j are already
> >> swapped and stay consistent, but when using an array in source
> >> code, they have to be flipped.
> >
> > I'm not sure what code you are using, but it prints out just
> > fine for me:
> >
> > https://run.dlang.io/is/hrA0tj
> >
> > -Steve
>
> Ah, here's a simple example:
>
> int[][] data3 =
>   [
>   [1, 0, 1, 0, 0],
>   [1, 0, 1, 0, 0],
>   [1, 0, 1, 1, 1],
>   [1, 0, 0, 1, 0],
>   [5, 1, 1, 1, 0]
>   ];
>
>   for(int i = 0; i < 5; i++)
>   {
>   for(int j = 0; j < 5; j++)
>   {
>   write(data4[i][j]," ");
>   }
>   writeln();
>   }
>
>1 0 1 0 0
>1 0 1 0 0
>1 0 1 1 1
>1 0 0 1 0
>5 1 1 1 0
>
> I have to draw j's first. I have to iterate through the
> "y"/columns/j to get the the "x's" first.
>
> I mean, I guess it makes sense if the outer-most array indexer
> refers to the inner-most "element".
>
> Wait, this IS the same as C, isn't it? So maybe this is just a
> "new" problem for me since I rarely-if-ever use hardcoded
> arrays...
>
> Maybe my brain is just melting.

The situation is bascially the same as C, though trying to make the type
syntax more consistent by putting it all on the left-hand side of the
variable has made things more confusing. The types read basically the same
as in C. The primary difference is that in D, the static array sizes go with
the type and not the variable name, which means that they're on the
left-hand side rather than the right. So, you get

int[5][4] arr;

instead of

int arr[4][5];

In both cases, the type is read outward from the variable name (which is
basically how the compiler reads types in both C and D, though understanding
that is more critical in C because of C's function pointer syntax). It's
just that in the D case, this then seems backwards, because when you then
index the array, the left index has $ of 4 and the right has $ of 5, which
is the reverse of the order in the declaration, whereas in C, the order
matches, because the sizes went on the right-hand side. One sort of
consistency was traded for another. With dynamic arrays, the sizes are
always given on the right-hand side, so you don't get that reversal. So,
what D does is reasonably consistent and matches C in terms of how types are
read, but it does end up being annoyingly hard to wrap your head around,
because the result is that the sizes of multi-dimensional, static arrays are
then declared in the opposite order from the order that they're accessed in.
If it weren't for the fact that D does out-of-bounds checking for all array
accesses in @safe code or when -release is not used, it would likely to be a
huge problem with such arrays in practice. Fortunately, since the checks are
almost always in place, the inevitable mistakes are usually quickly caught.

- Jonathan M Davis





Re: Compile time sequences

2018-10-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, October 4, 2018 5:44:55 AM MDT drug via Digitalmars-d-learn 
wrote:
> I was incorrect with description of the problem. The problem is that
> there is no simple way to distinct types and symbols if symbols are
> private. Because private symbol is not accessible you can not get any
> info on it, including is it type or symbol or value. And you can not get
> protection for types and values, because they have no protection at all.
> So you can not get protection for types and values and can not check if
> alias is type, value and symbol because it is private/protected. Vicious
> circle.
>
> Specific case https://run.dlang.io/is/CAoxXO
>
> Honestly, if `isType` can recognize private members the problem would be
> solved. But I think `isSymbol` and `isValue` (working with private
> members) will make situation more consistent.
>
>
> Current workaround with fields is using FieldNameTuple. But I fails to
> work around private enums.

It's a known issue that you can't properly do type introspection on private
symbols from other modules, and it needs to be fixed in the language. It
shouldn't be possible to actually use private symbols from other modules,
but it should be possible to get type information on them.

In his dconf talk this year, Andrei discussed adding wrappers around all of
the various traits that present the type information as a set of structs so
that you can easily and consistently get at it all instead of having to
piece it all together like you do now. He has a partial prototype, though I
don't know if he's made it public aside from what he showed in his sides,
and it's just wrapping the current stuff, so it's not addding any
information, just better organizing it. However, to get where he wants to go
with it, problems like this with private symbols are pretty much going to
have to be solved. Either way, the access level issues are a language issue
and not something that can be fixed by std.traits.

- Jonathan M Davis





Re: Dlang tour - Unittesting example

2018-10-02 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, October 2, 2018 3:59:28 AM MDT bauss via Digitalmars-d-learn 
wrote:
> On Tuesday, 2 October 2018 at 04:13:01 UTC, Joe wrote:
> > There appears to be a problem with the example at
> >
> > https://tour.dlang.org/tour/en/gems/unittesting
> >
> > If compiled with -unittest, the resulting program crashes. It
> > happens with ldc2 on Linux but it can also be seen if you click
> > on "Export" and run it with dmd -unittest.
>
> I think it's more likely a problem with your OS.
>
> I am unable to reproduce that with either of dmd or ldc.

IIRC, we use stdc for formatting floating values and not pure D code
(because correctly converting floating point values to strings is really,
really complicated to implement). So, the result is going to depend on the
system that it's run on. It fails on my system (64-bit FreeBSD). Honestly,
this is basically the same thing as comparing floating point values with ==.
You shouldn't do it. So, I'd argue that it's just plain a bad example.

- Jonathan M Davis





Re: How to convert this function into a template ?

2018-10-02 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, October 2, 2018 6:09:53 AM MDT Vinod K Chandran via Digitalmars-
d-learn wrote:
> On Tuesday, 2 October 2018 at 11:49:06 UTC, Jonathan M Davis
>
> wrote:
> > Why do you have a function for that? All you need to do is use
> > the append operator. e.g.
> >
> > x ~= value;
> >
> > - Jonathan M Davis
>
> Thanks for the reply. I did not find that it in documentation.
> Ofcourse i lost a chance to learn about templates. By translating
> a well known function into a template, i can easiy learn the
> concept, since the template documentation is little bit hard to
> understand.

The template equivalent would have been something like

void arrayAdd(T)(ref T[] x, T value)
{
auto index = x.length;
x.length += 1;
x[index] = value;
}

But if you're new to the language, I'd suggest that you read this site /
book:

http://ddili.org/ders/d.en/index.html

- Jonathan M Davis





Re: How to convert this function into a template ?

2018-10-02 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, October 2, 2018 5:40:18 AM MDT Vinod K Chandran via Digitalmars-
d-learn wrote:
> Hi all,
> I have a function and i want to convert this into a template so
> that i can use this function for more than one data type.
> This is my function.
> ```D
> void ArrayAdd( ref int[] x, int value) {
>  int index = x.length ;
>  x.length += 1 ;
>  x[index] = value ;
> }
> ```

Why do you have a function for that? All you need to do is use the append
operator. e.g.

x ~= value;

- Jonathan M Davis





Re: Can I create static c callable library?

2018-09-27 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, September 27, 2018 6:16:13 AM MDT Atila Neves via Digitalmars-
d-learn wrote:
> On Tuesday, 25 September 2018 at 14:13:50 UTC, Jacob Carlborg
>
> wrote:
> > On Tuesday, 25 September 2018 at 12:05:21 UTC, Jonathan M Davis
> >
> > wrote:
> >> If you use -betterC, then it's trivial, because your D program
> >> is restricted to extern(C) functions and features which don't
> >> require druntime. It can also be done without -betterC (and
> >> thus with druntime), but it gets to be _way_ more of a pain,
> >> because it requires that you manually initialize druntime -
> >> either by forcing whatever is using your "C" library to call a
> >> specific function to initialize druntime before using any of
> >> its normal functions or by having every function in the
> >> library check whether druntime has been initialized yet and
> >> initialize it if it hasn't been before it does whatever it's
> >> supposed to do.
> >
> > Shouldn't it be possible to use a C initialization function,
> > i.e. pragma(crt_constructor) to initialize druntime? Then it
> > only needs to be initialized once and it's not required to
> > check if it's initialized all the time.
> >
> > --
> > /Jacob Carlborg
>
> Even easier, compile this C file and add the resulting object
> file to your (now mostly) D static library:
>
> ---
> extern int rt_init(void);
> extern int rt_term(void);
>
> __attribute__((__constructor__)) void dinit(void) {
>  rt_init();
> }
> __attribute__((__destructor__)) void dterm(void) {
>  rt_term();
> }
> ---
>
> The C runtime will initialise the D runtime for you.

That's a neat trick.

- Jonathan M Davis





Re: Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?

2018-09-27 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, September 27, 2018 2:44:25 AM MDT Chad Joan via Digitalmars-d-
learn wrote:
> The spec seems to have the homogeneous cases covered: classes
> with classes or structs with structs.  What I'm more worried
> about is stuff like when you have a class compared to a struct or
> builtin type, or maybe a struct compared to a builtin type
> (especially more complicated builtin types like arrays!).  The
> homogeneous cases are important for making a type consistent with
> itself, but the other cases are important for integrating a type
> with everything else in the ecosystem.
>
> Notably, "alias this" is awesome and has more or less solved that
> for me in the pedestrian cases I tend to encounter.  I can write
> a struct and alias this to some reference variable that will be
> representative of my struct's "nullness" or other states of
> existence.
>
> But I wouldn't be surprised if there are corner-cases I haven't
> encountered yet (actually I think I just remembered that this bit
> me a little bit once or twice) where having a single alias-this
> isn't sufficient to cover all of the possible things my
> struct/class could be compared to (ex: if the type's null-state
> corresponded to int.max for ints and float.nan for floats, and
> you can't just use opEquals, such as when the type is a class and
> could be precisely null).

For two types to be compared, they must be the the same type - or they must
be implicitly convertible to the same type, in which case, they're converted
to that type and then compared. So, as far as D's design of comparison goes,
there is no need worry about comparing differing types. At most, you need to
worry about what implicit type conversions exist, and D isn't big on
implicit type conversions, because they tend to cause subtle bugs. So, while
they definitely affect comparison, they don't affect anywhere near as much
as they would in a language like C++. In general, you're not going to get
very far if you're trying to make it possible to compare a user-defined type
against other types in D without explicitly converting it first.

- Jonathan M Davis





Re: Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?

2018-09-27 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, September 27, 2018 1:41:23 AM MDT Chad Joan via Digitalmars-d-
learn wrote:
> On Thursday, 27 September 2018 at 05:12:06 UTC, Jonathan M Davis

> This is also reminding me of how it's always bugged me that there
> isn't a way to operator overload opEquals with a static method
> (or even a free function?), given that it would allow the
> class/struct implementer to guard against (or even interact
> intelligently with) null values:

That's not really an issue with D. With classes, when you have a == b, it
doesn't lower to a.opEquals(b). Rather, it lowers to opEquals(a, b), and the
free function opEquals is defined as

bool opEquals(Object lhs, Object rhs)
{
// If aliased to the same object or both null => equal
if (lhs is rhs) return true;

// If either is null => non-equal
if (lhs is null || rhs is null) return false;

// If same exact type => one call to method opEquals
if (typeid(lhs) is typeid(rhs) ||
!__ctfe && typeid(lhs).opEquals(typeid(rhs)))
/* CTFE doesn't like typeid much. 'is' works, but opEquals 
doesn't
(issue 7147). But CTFE also guarantees that equal TypeInfos are
always identical. So, no opEquals needed during CTFE. */
{
return lhs.opEquals(rhs);
}

// General case => symmetric calls to method opEquals
return lhs.opEquals(rhs) && rhs.opEquals(lhs);
}

/
* Returns true if lhs and rhs are equal.
*/
bool opEquals(const Object lhs, const Object rhs)
{
// A hack for the moment.
return opEquals(cast()lhs, cast()rhs);
}

So, it already takes care of checking for null or even if the two references
point to the same object. For structs, a == b, does lower to a.opEquals(b),
but for better or worse, structs are designed so that their init values need
to be valid, or you're going to have problems in general. Trying to work
around that is fighting a losing battle.

> Wouldn't it be helpful to have a root class type just to have a
> "Top" type at runtime, even if it had no members?  Ex: so you
> could do things like make an array ProtoObject[] foo; that can
> contain any runtime polymorphic variables.

Maybe? It's not something that I've personally found to be particularly
useful. Once you can templatize code, the need to have a common base class
gets pretty hard to argue for, but I don't know that it's non-existent.
Also, for better or worse, you can already get it with void* - and cover
more types no less (albeit less @safely). But from what I understand of what
Andrei is intending, ProtoObject will end up being the new root class for
all D classos, so having ProtoObject[] would work for all extern(D) classes.
Of course, that still potentially leaves exern(C++) classes and interfaces
(which could be extern(C++) or COM even right now and aren't derived from
Object). So, things are already a bit weird with classes when you start
interacting with other languages through D. is(T : Object) and
is(T == class) do _not_ mean quite the same thing even though you'd think
that they would. And I haven't done enough with extern(C++) or COM in D to
claim to understand all of the subtleties. If you're not messing with them
directly or writing generic code that's going to mess with them, it doesn't
really matter though.

-Jonathan M Davis





Re: Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?

2018-09-26 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, September 26, 2018 10:20:58 PM MDT Chad Joan via Digitalmars-
d-learn wrote:
> On Wednesday, 26 September 2018 at 23:32:36 UTC, Jonathan M Davis
>
> wrote:
> > On Wednesday, September 26, 2018 3:24:07 PM MDT Adam D. Ruppe
> >
> > via Digitalmars-d-learn wrote:
> >> Object.factory kinda sux and I'd actually like to remove it
> >> (among other people). There's no plan to actually do that, but
> >> still, just on principle I want to turn people away.
> >
> > While there may not currently be plans to be remove it, as
> > there _are_ plans to add ProtoObject as the new root class
> > underneath Object, at some point here, it's likely that a large
> > percentage of classes won't have anything to do with Object, so
> > relying on Object.factory to be able to construct class Objects
> > in general isn't likely to be a viable path in the long term -
> > though presumably it would work for a code base that's written
> > specifically with it in mind.
> >
> > Personally, I'm hoping that we eventually get to the point
> > where Walter and Andrei are willing to outright deprecate
> > Object itself, but I expect that ProtoObject will have to have
> > been in use for a while before we have any chance of that
> > happening. Either way, I think that it's clear that most code
> > bases should go with a solution other than Object.factory if at
> > all reasonably possible.
> >
> > - Jonathan M Davis
>
> That's interesting!  Thanks for mentioning.
>
> If you don't mind, what are the complaints regarding Object?  Or
> can you link me to discussions/issues/documents that point out
> the shortcomings/pitfalls?
>
> I've probably run into a bunch of them, but I realize D has come
> a long way since that original design and I wouldn't be surprised
> if there's a lot more for me to learn here.

I can point you to the related DIP, though it's a WIP in progress

https://github.com/andralex/DIPs/blob/ProtoObject/DIPs/DIP.md

There are also these enhancement requests for removing the various member
functions from Object (though they're likely to be superceded by the DIP):

https://issues.dlang.org/show_bug.cgi?id=9769
https://issues.dlang.org/show_bug.cgi?id=9770
https://issues.dlang.org/show_bug.cgi?id=9771
https://issues.dlang.org/show_bug.cgi?id=9772

Basically, the problems tend to come in two areas:

1. Because of how inheritance works, once you have a function on a class,
you're forcing a certain set of attributes on that function - be it type
qualifiers like const or shared or scope classes like pure or @safe. In some
cases, derived classes can be more restricted when they override the
function (e.g. an overide can be @safe when the original is @system), but
that only goes so far, and when you use the base class API, you're stuck
with whatever attributes it has. Regardless, derived classes can't be _less_
restrictive. In fact, the only reason that it's currently possible to use ==
with const class references in D right now is because of a hack. The free
function opEquals that gets called when you use == on two class references
actually casts away const so that it can then call the member function
opEquals (which doesn't work with const). So, if the member function
opEquals mutates the object, you actuall get undefined behavior. And because
Object.opEquals defines both the parameter and invisible this parameter as
mutable, derived classes have to do the same when they override it;
otherwise, they'd be overloading it rather than overriding it.

Object and its member functions really come from D1 and predate all of the
various attributes in D2 - including const. But even if we could just add
all of the attributes that we thought should be there without worrying about
breaking existing code, there would be no right answer. For instance, while
in the vast majority of cases, opEquals really should be const, having it be
const does not work with types that lazily initialize some members (since
unlike in C++, D does not have backdoors for const - when something is
const, it really means const, and it's undefined behavior to cast away const
and mutate the object). So, having Object.opEquals be const might work in
99% of cases, but it wouldn't work in all. The same could be said for other
attributes such as pure or nothrow. Forcing a particular set of attributes
on these functions on everyone is detrimental. And honestly, it really isn't
necessary.

Having them on Object comes from a Java-esque design where you don't have
templates. With proper templates like D2 has, there normally isn't a reason
to operate on an Object. You templatize the code rather than relying on a
common base class. So, there's no need to have Object.toString in order have
toString for all classes or Object.opEquals to have opEquals for all
classes. Each class can define it however it sees fit. Now, once a
particular class in a hierarchy has defined a function like opEquals or
toString, that affects any classes derived from it, but then only the

Re: Is there a way to use Object.factory with templated classes? Or some way to construct templated classes given RTTI of an instance?

2018-09-26 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, September 26, 2018 3:24:07 PM MDT Adam D. Ruppe via 
Digitalmars-d-learn wrote:
> Object.factory kinda sux and I'd actually like to remove it
> (among other people). There's no plan to actually do that, but
> still, just on principle I want to turn people away.

While there may not currently be plans to be remove it, as there _are_ plans
to add ProtoObject as the new root class underneath Object, at some point
here, it's likely that a large percentage of classes won't have anything to
do with Object, so relying on Object.factory to be able to construct class
Objects in general isn't likely to be a viable path in the long term -
though presumably it would work for a code base that's written specifically
with it in mind.

Personally, I'm hoping that we eventually get to the point where Walter and
Andrei are willing to outright deprecate Object itself, but I expect that
ProtoObject will have to have been in use for a while before we have any
chance of that happening. Either way, I think that it's clear that most code
bases should go with a solution other than Object.factory if at all
reasonably possible.

- Jonathan M Davis





Re: Can I create static c callable library?

2018-09-25 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, September 25, 2018 5:03:11 AM MDT John Burton via Digitalmars-d-
learn wrote:
> I need to write a library to statically link into a c program.
> Can I write this library in D?
> Will I be able to use proper D abilities like gc? Obviously the
> public interface will need to be basic c callable functions...
>
> I 'main' is a c program will this work?

If you use -betterC, then it's trivial, because your D program is restricted
to extern(C) functions and features which don't require druntime. It can
also be done without -betterC (and thus with druntime), but it gets to be
_way_ more of a pain, because it requires that you manually initialize
druntime - either by forcing whatever is using your "C" library to call a
specific function to initialize druntime before using any of its normal
functions or by having every function in the library check whether druntime
has been initialized yet and initialize it if it hasn't been before it does
whatever it's supposed to do. And of course, if you pass any GC-allocated
memory out of the library, you have to worry about calling all of the
appropriate GC functions so that it knows not to free it and knowing when to
tell the GC that that memory can be freed. It's all very feasible and all
very annoying. In general, it's far, far easier to write D programs that
call into C code than to write C programs that call into D code. That's part
of why some folks are so excited about -betterC. It makes it _way_ easier to
write D libraries that can be called from C or C++ - though because you lose
out on so many D features in the process (like the GC), whether it's even
worth it is highly debatable.

- Jonathan M Davis





Re: Is it possible to translate this API's C headers?

2018-09-19 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, September 18, 2018 7:39:40 AM MDT Atila Neves via Digitalmars-d-
learn wrote:
> On Monday, 17 September 2018 at 19:13:06 UTC, Jonathan M Davis
>
> wrote:
> > On Monday, September 17, 2018 7:43:21 AM MDT Kagamin via
> >
> > Digitalmars-d-learn wrote:
> >> try dpp https://github.com/atilaneves/dpp
> >
> > Since according to Mike's post, it's C++ code, dpp wouldn't
> > help, because it currently only supports C and not C++.
> >
> > - Jonathan M Davis
>
> It does C++ as well, just not all (or even close at this point)
> of it. I doubt it'd work on any real C++ codebase right now, but
> who knows. It definitely won't if any of the headers use the
> standard library, which is likely to happen.

Well, the repo claims that it currently only does C - hence why I said that
it will only do C (though even if it partially supports C++, odds are it's
not enough to matter unless you know what you're doing - which the OP
clearly doesn't, since they don't know C/C++).

> It turns out that parsing C++ is a lot of work. Who knew? :P

Yeah...

- Jonathan M Davis





Re: Is it possible to translate this API's C headers?

2018-09-17 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, September 17, 2018 7:43:21 AM MDT Kagamin via Digitalmars-d-learn 
wrote:
> try dpp https://github.com/atilaneves/dpp

Since according to Mike's post, it's C++ code, dpp wouldn't help, because it
currently only supports C and not C++.

- Jonathan M Davis





Re: Pass 'this' as reference

2018-09-15 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, September 15, 2018 11:44:05 AM MDT Jan via Digitalmars-d-learn 
wrote:
> On Thursday, 13 September 2018 at 11:08:30 UTC, Jonathan M Davis
>
> wrote:
> > [...]
>
> Thanks for clarifying Jonathan :)
> But aren't the variables considered rvalues then?

No. variables are _always_ lvalues. An lvalue is an object which is
addressable and which can therefore be assigned a value (ignoring issues of
constness). The name comes from the fact that lvalues are allowed on the
left-hand side of an assignment operation, whereas rvalues are only allowed
on the right. e.g.

int i;
int* p;

are both lvalues. They have addresses and can be assigned to.

i = 42;
p = 
auto p2 = 

On the other hand, the return value of

int foo(string s);

is an rvalue. How it's actually stored is compiler-defined; you can't take
its address, and you can't assign to it.

foo("bar") = 42; // illegal
auto p = ("bar"); // illegal

On the other hand,

ref int foo(string s);

returns by ref, so it's returning an lvalue. Its address can be taken, and
it can be assigned a value.

foo("bar") = 42; // legal
auto p = ("bar"); // legal

Because a pointer or reference points to a specific address, even if the
pointer itself is an rvalue, what it points to is almost always an lvalue,
(the main case where it isn't an lvalue would be something like a function
pointer, since you can take a function's address, but you can't assign to
it). So, something like

int* foo(string s);
*foo("bar") = 42;

compiles. However, ultimately, you can't know whether a particular value is
an lvalue or rvalue without context. A variable is always an lvalue, whereas
a return value usually isn't - but it can be if it's returned by ref. And a
variable and return value could both be the same type - int, int*, string,
etc. So, the type itself doesn't tell you whether something is an lvalue or
rvalue. It's how it's stored that tells you.

Ultimately though, if you want to know whether something is an lvalue or
rvalue, consider whether it's something that can go on the left-hand side of
an assignment operation (ignoring its constness), or whether it can only go
on the right-hand side.

https://msdn.microsoft.com/en-us/library/f90831hc.aspx
https://stackoverflow.com/questions/17357888/exact-difference-between-rvalue-and-lvalue
https://www.quora.com/What-is-lvalue-and-rvalue-in-C

- Jonathan M Davis





Re: dealing with very long paths and names

2018-09-15 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, September 15, 2018 8:45:55 AM MDT Vladimir Panteleev via 
Digitalmars-d-learn wrote:
> On Friday, 14 September 2018 at 21:16:31 UTC, Jonathan M Davis
>
> wrote:
> > Yeah, though if you write cross-platform applications or
> > libraries (and ideally, most applications and libraries would
> > be platform-agnostic), you can't necessarily avoid all of the
> > Windows insanity, even if you yourself use a platform without
> > those problems.
>
> Linux generally allows you to go ahead and use the filesystem as
> a database, and this works pretty well in a lot of cases.
> Filesystem performance is much better, and so are the limitations
> - not just the path length as discussed in this thread, but also
> the range of valid characters (anything except / and NUL is
> fine). Plus, depending on your choice of filesystem, you get
> bonus features like snapshots, incremental backups, and
> deduplication. It's a boon for prototyping (or Linux-only
> software).

Oh, I don't disagree. I think that in general it makes _way_ more sense to
use a *nix system for development (or most anything else) even if the
software can run on multiple platforms. And actually, the primary reason
that I use the OS I do (FreeBSD) is because of the filesystem (it has first
class ZFS support unlike Linux). However, I'm a strong believer that in
general, software should be cross-platform if it reasonably can be. That's
usually the worst when folks use all kinds of Windows-specific stuff when
they don't need to, but sometimes, Linux-isms do creep into code
unnecessarily.

Either way, while I've occasionally found something that Windows did better
than *nix, far more often, it's shocking how bad their APIs are. And in this
particular case, there really isn't a great solution. Trying to hide the
Windows limitations by translating longer paths so that the Windows API is
risky business, but leaving it up to the programmer to run into it and then
scream in frustration like the OP is isn't great either. And of course, even
if they outright fixed the problem in Windows tomorrow, it would probably be
over a decade before you could rely on it given how long people use older
versions of Windows.

- Jonathan M Davis





Re: array to string functional?

2018-09-14 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, September 14, 2018 11:39:48 PM MDT berni via Digitalmars-d-learn 
wrote:
> On Saturday, 15 September 2018 at 03:25:38 UTC, Paul Backus wrote:
> > On Friday, 14 September 2018 at 20:43:45 UTC, SrMordred wrote:
> >> What you want is std.range.chunks
> >>
> >>
> >> auto a = [1,0,1,1,1,0,1,0,1,1,1,1,0];
> >>
> >> a.map!(to!string)
> >>
> >>  .join("")
> >>  .chunks(4)
> >>  .map!(to!string) //don´t know why the chunks are not
> >>
> >> already strings at this point ;/
> >>
> >>  .writeln;
> >
> > It's easier if you chunk before joining:
> >
> > auto a = [1,0,1,1,1,0,1,0,1,1,1,1,0];
> >
> > a.map!(to!string)
> >
> >  .chunks(4)
> >  .map!join
> >  .writeln;
>
> Oh, thanks. What I didn't know about was join. Now I wonder how I
> could have found out about it, without asking here? Even yet I
> know it's name I cannot find it, nighter in the language
> documentation nor in the library documentation.

https://dlang.org/phobos/std_array.html#join

- Jonathan M Davis






Re: dealing with very long paths and names

2018-09-14 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, September 14, 2018 2:52:42 PM MDT H. S. Teoh via Digitalmars-d-
learn wrote:
> On Fri, Sep 14, 2018 at 07:05:35PM +, Basile B. via Digitalmars-d-
learn wrote:
> > On Friday, 14 September 2018 at 17:59:38 UTC, Josphe Brigmo wrote:
> > > Seems to break dirEntries when trying to deal with long pathnames(>
> > > 512) on windows.
> > >
> > > It's a strange error because it just fails with access denied or
> > > missing file.
> >
> > The bug is known, see https://issues.dlang.org/show_bug.cgi?id=8967
>
> Whoa.  After seeing the insane mess that is the Windows pathname syntax,
> I'm so glad I code on Linux instead!

Yeah, though if you write cross-platform applications or libraries (and
ideally, most applications and libraries would be platform-agnostic), you
can't necessarily avoid all of the Windows insanity, even if you yourself
use a platform without those problems.

- Jonathan M Davis





Re: Pass 'this' as reference

2018-09-13 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, September 13, 2018 4:04:58 AM MDT Jan via Digitalmars-d-learn 
wrote:
> Many thanks Adam and Steve! Works like a charm! :D
> I presumed classes are lvalues. I shouldn't make things more
> complicated than they are ;-)

Well, the variables _are_ lvalues. It's just that they're references to
objects rather than the objects themselves. You never refer to a class
object directly in D. Rather, you're always dealing with a reference to a
class object. Class references are basically pointers except that you can't
dereference them directly, just call member functions on them (which in D
means implicitly dereferencing whether you're talking about pointers or
class references). In that respect, they're like classes in Java. So, if you
assign a value to a class reference, you're assigning the reference, not the
class object itself, just like when you assign a value to a pointer, you're
mutating the pointer itself, not mutating the object that it points to.

- Jonathan M Davis





Re: Shared, ref, arrays, and reserve template instantiation

2018-09-13 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, September 12, 2018 9:42:19 PM MDT James Blachly via 
Digitalmars-d-learn wrote:
> Neia is right that I tried to cast as in the second case ( but
> without UFCS -- reserve( cast(int[]), N); ).  As an aside, what
> is going on behind the scenes with the compiler when casting away
> a property? I did not think cast operations copied data, so was
> surprised that a cast value is not an lvalue.

Well, you basically get a temporary variable when you cast an object, and
those are rvalues. And while casting with regards to type qualifiers such as
const or shared, you're not actually changing the data, plenty of other
casts do - e.g. float and long don't even have the same size, but you can
cast from one to the other. So, even in principle, only some casts could
result in lvalues even if we wanted them to.

- Jonathan M Davis





Re: Shared, ref, arrays, and reserve template instantiation

2018-09-12 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, September 12, 2018 5:41:16 PM MDT James Blachly via 
Digitalmars-d-learn wrote:
> When I add the "shared" attribute to an array, I am no longer
> able to call reserve because the template won't instantiate:
>
> Error: template object.reserve cannot deduce function from
> argument types !()(shared(int[]), int), candidates are:
> /dlang/dmd/linux/bin64/../../src/druntime/import/object.d(4091):
>object.reserve(T)(ref T[] arr, size_t newcapacity)
>
> 1. Shared modifies the type, so the template does not match. Even
> casting does not seem to work however. Is there something about
> shared that makes it unable to be taken by reference?
> 2. Is there a workaround for me to be able to preallocate the
> array?

You can't do much of anything with shared while it's shared, which is pretty
much the whole point. The way that shared needs to be used in general is
essentially

synchronized(mutexForSharedObj)
{
auto local = cast(Type)sharedObj;
// do stuff with local...

// ensure that no thread-local references to local / sharedObj exist
// before releasing the mutex
}

// shared object is now essentially unusable again

Doing pretty much _any_ operation on a shared object while it's shared
(other than atomic operations from core.atomic) is wrong, because it's not
thread-safe. The compiler prevents most operations but not as many as it
should (e.g. copying is currently legal). That will likely be fixed in the
future, but exactly what's going to happen to shared in all of the fine
details hasn't been sorted out yet. The basics work, but not all of the
details are as they should be yet.

So, if you're doing anything like calling reserve or ~= on a shared array,
then you need to protect it with the mutex that you have for it and cast
away shared first. However, if you're just dealing with constructing the
array, then what you should do is create it as thread-local and then cast it
to shared after you're done setting it up and are ready to share it across
threads (after which, all further operations on it should be protected by a
mutex or use atomics, otherwise they're not thread-safe).

- Jonathan M Davis





Re: Bug with writeln?

2018-09-10 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, September 9, 2018 8:30:12 AM MDT Saurabh Das via Digitalmars-d-
learn wrote:
> Thank you for explaining all this.
>
> It is frustrating because the behaviour is very counterintuitive.
>
> I will use a workaround for now.

Ranges are fantastic, and the basic concept is solid, but a number of the
implementation details really weren't worked out well enough in the
beginning, which means that there's a lot of stuff that works reasonably
well with ranges but falls apart on some level in certain circumstances -
and what happens when ranges get copied is a big part of that.

On some level, it's what we get for being the first language to really
implement ranges as part of its standard library. As I understand it, Andrei
didn't create the concept, but AFAIK, it wasn't implemented on any real
scale by anyone prior to them being added to Phobos. And when you're the
first to implement something, you often screw it up on some level. With many
things, D was able to learn from C++ and improve, but this is an area where
we got to make new mistakes. The result is something that's extremely useful
and largely works but which has some problematic corner cases that really
shouldn't be there.

- Jonathan M Davis





Re: "immutable string" vs "const string*"

2018-09-09 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, September 9, 2018 2:49:56 AM MDT rikki cattermole via 
Digitalmars-d-learn wrote:
> On 09/09/2018 8:41 PM, Christian Mayer wrote:
> > On Sunday, 9 September 2018 at 08:14:41 UTC, rikki cattermole wrote:
> >> Are you aware that a string is just an alias of immutable(char)[]?
> >
> > Yes, I'm aware of that. But it's the same, for example, with just one
> > char. "immutable char" vs "const char*".
> >
> > Or int, or any other data type. As of my current understanding "char"
> > will create a new variable and copy the content of the original to the
> > new variable. "char*" will just use the pointer. And "const char*" is
> > good for when not modifying. But I also can achieve the same using
> > "immutable char". But I'm not sure when better using "immutable char".
> >
> > In C I would rather use a const pointer. But since I just started
> > learing D I'm not so sure because there are so many ways.
>
> Don't over think it. The only thing you're doing by micro-optimization
> is causing potential problems that wouldn't otherwise exist.

Yeah. I don't know if I've ever seen any D code take a string*. There's
really no reason to. If the string is just being passed in, then it's going
to be string. If you have an array of strings, then that's what you'd pass.
And if you want to mutate the string that's being passed in, then you'd pass
by ref. Just about the only time that I'd expect pointers to be used with
relation to strings in D is if you're calling C functions, and you need to
pass a null-terminated string.

- Jonathan M Davis





Re: Bug with writeln?

2018-09-06 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, September 6, 2018 1:05:03 PM MDT Steven Schveighoffer via 
Digitalmars-d-learn wrote:
> On 9/6/18 2:52 PM, Jonathan M Davis wrote:
> > On Thursday, September 6, 2018 12:21:24 PM MDT Steven Schveighoffer via
> >
> > Digitalmars-d-learn wrote:
> >> On 9/6/18 12:55 PM, Jonathan M Davis wrote:
> >>> It's not a bug in writeln. Any time that a range is copied, you must
> >>> not
> >>> do _anything_ else with the original unless copying it is equivalent
> >>> to
> >>> calling save on it, because the semantics of copying a range are
> >>> unspecified. They vary wildly depending on the range type (e.g.
> >>> copying
> >>> a dynamic array is equivalent to calling save, but copying a class
> >>> reference is not). When you pass the range to writeln, you must
> >>> assumed
> >>> that it may have been consumed. And since you have range of ranges,
> >>> you
> >>> must assume that the ranges that are contained may have been consumed.
> >>> If you want to pass them to writeln and then do anything else with
> >>> them, then you'll need to call save on every range involved (which is
> >>> a
> >>> bit of a pain with a range of ranges, but it's necessary all the
> >>> same).
> >>
> >> This is not necessarily true. It depends how the sub-ranges are
> >> returned.
> >>
> >> The bug is that formattedWrite takes ranges sometimes by ref, sometimes
> >> not.
> >>
> >> formattedWrite should call save on a forward range whenever it makes a
> >> copy, and it doesn't.
> >>
> >> Case in point, it doesn't matter if you call writeln(b.save), the same
> >> thing happens.
> >
> > That's still not a bug in formattedWrite. save only duplicates the
> > outer-most range. And since writeln will ultimately iterate through the
> > inner ranges - which weren't saved - you end up with them being
> > consumed.
>
> That is the bug -- formattedWrite should save all the inner ranges
> (writeln calls formattedWrite, and lets it do all the work). To not do
> so leaves it open to problems such as consuming the sub ranges.
>
> I can't imagine that anyone would expect or desire the current behavior.

It's exactly what you're going to get in all cases if the ranges aren't
forward ranges, and it's what you have to do in general when passing ranges
of ranges to functions if you want to be able to continue to use any of the
ranges involved after passing them to the function. Changing formattedWrite
to work around it is only a workaround for this paricular case. It's still
a bug in general - though given that this would be one of the more common
cases, working around it in this particular case may be worth it. It's still
a workaround though and not something that can be relied on in with
range-based code in general - especially when most range-based code isn't
written to care about what the element types are and copies elements around
all the time.

> Ironically, when that bug is fixed, you *don't* have to call save on the
> outer range!

Except you do, because it's passed by value. If it's a dynamic array, then
you're fine, since copying saves, but in the general case, you still do.

> > When you're passing a range of ranges to a function, you need to
> > recursively save them if you don't want the inner ranges in the
> > original range to be consumed. Regardless of what formattedWrite does,
> > it's a general issue with any function that you pass a range of ranges.
> > It comes right back to the same issue of the semantics of copying
> > ranges being unspecified and that you therefore must always use save on
> > any ranges involved if you want to then use those ranges after having
> > passed them to a function or copy them doing anything else. It's that
> > much more annoying when you're dealing with a range of ranges rather
> > than a range of something else, but the issue is the same.
> It's only a problem if the subranges are returned by reference. If they
> aren't, then no save is required (because they are already copies). The
> fix in this case is to make a copy if possible (using save as expected).
>
> I think the save semantics have to be one of the worst designs in D.

On that we can definitely agree. I'm strongly of the opinion that it should
have been required that forward ranges be dynamic arrays or structs (no
classes allowed) and that it be required that they have a postblit / copy
constructor if the default copy wasn't equivalent to save. If you wanted a
class that was a forward range, you would then have to wrap it in a struct
with the appropriate postblit / copy constructor. That way, copying a
forward range would _always_ be saving it.

The harder question is what to then do with basic input ranges. Having them
share code with forward ranges is often useful but also frequently a
disaster, and to really be correct, they would need to either be full-on
reference types or always passed around by reference. Allowing partial
reference types is a total disaster when you're allowed to copy the range.
Requiring that they be classes would 

Re: Bug with writeln?

2018-09-06 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, September 6, 2018 12:21:24 PM MDT Steven Schveighoffer via 
Digitalmars-d-learn wrote:
> On 9/6/18 12:55 PM, Jonathan M Davis wrote:
> > On Thursday, September 6, 2018 2:40:08 AM MDT Saurabh Das via
> > Digitalmars-d->
> > learn wrote:
> >> Is this a bug with writeln?
> >>
> >> void main()
> >> {
> >>
> >>   import std.stdio, std.range, std.algorithm;
> >>
> >>   auto a1 = sort([1,3,5,4,2]);
> >>   auto a2 = sort([9,8,9]);
> >>   auto a3 = sort([5,4,5,4]);
> >>
> >>   pragma(msg, typeof(a1));
> >>   pragma(msg, typeof(a2));
> >>   pragma(msg, typeof(a3));
> >>
> >>   auto b = [a1, a2, a3];
> >>   pragma(msg, typeof(b));
> >>
> >>   writeln("b:");
> >>   writeln(b);
> >>   writeln(b);  // <-- this one prints incorrectly
> >>
> >>   writeln("a:");
> >>   writeln(a1);
> >>   writeln(a2);
> >>   writeln(a3);
> >>
> >> }
> >>
> >> Output
> >> ==
> >>
> >> SortedRange!(int[], "a < b")
> >> SortedRange!(int[], "a < b")
> >> SortedRange!(int[], "a < b")
> >> SortedRange!(int[], "a < b")[]
> >> b:
> >> [[1, 2, 3, 4, 5], [8, 9, 9], [4, 4, 5, 5]]
> >> [[], [], []]
> >> a:
> >> [1, 2, 3, 4, 5]
> >> [8, 9, 9]
> >> [4, 4, 5, 5]
> >>
> >> The issue goes away if I cast 'b' to const before writeln. I
> >> think it is a bug, but maybe I am missing something?
> >
> > It's not a bug in writeln. Any time that a range is copied, you must not
> > do _anything_ else with the original unless copying it is equivalent to
> > calling save on it, because the semantics of copying a range are
> > unspecified. They vary wildly depending on the range type (e.g. copying
> > a dynamic array is equivalent to calling save, but copying a class
> > reference is not). When you pass the range to writeln, you must assumed
> > that it may have been consumed. And since you have range of ranges, you
> > must assume that the ranges that are contained may have been consumed.
> > If you want to pass them to writeln and then do anything else with
> > them, then you'll need to call save on every range involved (which is a
> > bit of a pain with a range of ranges, but it's necessary all the same).
>
> This is not necessarily true. It depends how the sub-ranges are returned.
>
> The bug is that formattedWrite takes ranges sometimes by ref, sometimes
> not.
>
> formattedWrite should call save on a forward range whenever it makes a
> copy, and it doesn't.
>
> Case in point, it doesn't matter if you call writeln(b.save), the same
> thing happens.

That's still not a bug in formattedWrite. save only duplicates the
outer-most range. And since writeln will ultimately iterate through the
inner ranges - which weren't saved - you end up with them being consumed.
When you're passing a range of ranges to a function, you need to recursively
save them if you don't want the inner ranges in the original range to be
consumed. Regardless of what formattedWrite does, it's a general issue with
any function that you pass a range of ranges. It comes right back to the
same issue of the semantics of copying ranges being unspecified and that you
therefore must always use save on any ranges involved if you want to then
use those ranges after having passed them to a function or copy them doing
anything else. It's that much more annoying when you're dealing with a range
of ranges rather than a range of something else, but the issue is the same.

- Jonathan M Davis





Re: Slicing betterC

2018-09-06 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, September 6, 2018 11:34:18 AM MDT Adam D. Ruppe via 
Digitalmars-d-learn wrote:
> On Thursday, 6 September 2018 at 17:10:49 UTC, Oleksii wrote:
> > struct Slice(T) {
> >
> >   size_t capacity;
> >   size_t size;
> >   T* memory;
> >
> > }
>
> There's no capacity in the slice, that is stored as part of the
> GC block, which it looks up with the help of RTTI, thus the
> TypeInfo reference.
>
> Slices *just* know their size and their memory pointer. They
> don't know how they were allocated and don't know what's beyond
> their bounds or how to grow their bounds. This needs to be
> managed elsewhere.
>
> If you malloc a slice in regular D, the capacity will be returned
> as 0 - the GC doesn't know anything about it. Any attempt to
> append to it will allocate a whole new block.
>
> In -betterC, there is no GC to look up at all, and thus it has
> nowhere to look. You'll have to make your own struct that stores
> capacity if you need it.
>
> I like to do something like
>
> struct MyArray {
>T* rawPointer;
>int capacity;
>int currentLength;
>
>// most user interaction will occur through this
>T[] opSlice() { return rawPointer[0 .. currentLength]; }
>
>// fill in other operators as needed
> }

To try to make this even clearer, a dynamic array looks basically like this
underneath the hood

struct DynamicArray(T)
{
size_t length;
T* ptr;
}

IIRC, it actually uses void* unfortunately, but that struct is basically
what you get. Notice that _all_ of the information that's there is the
pointer and the length. That's it. If you understand the semantics of what
happens when passing that struct around, you'll understand the semantics of
passing around dynamic arrays. And all of the operations that would have
anything to do with memory management involve the GC - capacity, ~, ~=, etc.
all require the GC. If you're not using -betterC, the fact that the dynamic
array was allocated with malloc is pretty irrelevant, since all of those
operations will function exactly the same as if the dynamic array were
allocated by the GC. It's just that because the dynamic array is not
GC-allocated, it's guaranteed that the capacity is 0, and therefore any
operations that would increase the arrays length then require reallocating
the dynamic array with the GC, whereas if it were already GC-allocated, then
its capacity might have been greater than its length, in which case,
reallocation would not be required.

If you haven't read it already, I would suggest reading this article:

https://dlang.org/articles/d-array-article.html

It does not use the official terminology, but in spite of that, it should
really help clarify things for you. The article refers to T[] as being a
slice (which is accurate, since it is a slice of memory), but it incorrectly
refers to the memory buffer itself as being the dynamic array, whereas the
language spec considers the T[] (the struct shown above) to be the dynamic
array. The language does not have a specific name for that memory buffer,
and it considers a T[] to be dynamic array regardless of what memory it
refers to. So, you should keep that in mind when reading the article, but
the concepts that it teaches are very much correct and should help a great
deal in understanding how dynamic arrays work in D.

- Jonathan M Davis





Re: Bug with writeln?

2018-09-06 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, September 6, 2018 2:40:08 AM MDT Saurabh Das via Digitalmars-d-
learn wrote:
> Is this a bug with writeln?
>
> void main()
> {
>  import std.stdio, std.range, std.algorithm;
>
>  auto a1 = sort([1,3,5,4,2]);
>  auto a2 = sort([9,8,9]);
>  auto a3 = sort([5,4,5,4]);
>
>  pragma(msg, typeof(a1));
>  pragma(msg, typeof(a2));
>  pragma(msg, typeof(a3));
>
>  auto b = [a1, a2, a3];
>  pragma(msg, typeof(b));
>
>  writeln("b:");
>  writeln(b);
>  writeln(b);  // <-- this one prints incorrectly
>
>  writeln("a:");
>  writeln(a1);
>  writeln(a2);
>  writeln(a3);
>
> }
>
> Output
> ==
>
> SortedRange!(int[], "a < b")
> SortedRange!(int[], "a < b")
> SortedRange!(int[], "a < b")
> SortedRange!(int[], "a < b")[]
> b:
> [[1, 2, 3, 4, 5], [8, 9, 9], [4, 4, 5, 5]]
> [[], [], []]
> a:
> [1, 2, 3, 4, 5]
> [8, 9, 9]
> [4, 4, 5, 5]
>
> The issue goes away if I cast 'b' to const before writeln. I
> think it is a bug, but maybe I am missing something?

It's not a bug in writeln. Any time that a range is copied, you must not do
_anything_ else with the original unless copying it is equivalent to calling
save on it, because the semantics of copying a range are unspecified. They
vary wildly depending on the range type (e.g. copying a dynamic array is
equivalent to calling save, but copying a class reference is not). When you
pass the range to writeln, you must assumed that it may have been consumed.
And since you have range of ranges, you must assume that the ranges that are
contained may have been consumed. If you want to pass them to writeln and
then do anything else with them, then you'll need to call save on every
range involved (which is a bit of a pain with a range of ranges, but it's
necessary all the same).

In many cases, you can get away with passing a range to a function or use it
with foreach and then continue to use it after that, but that's only because
copying those ranges is equivalent to calling save on them. It doesn't work
if any of the ranges involved aren't saved when they're copied, and it
doesn't work in generic code, because you have no clue whether the ranges
that are going to be used with that code are going to be saved when they're
copied.

- Jonathan M Davis





Re: Function parameter type inference: is this example working as intended?

2018-09-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, September 4, 2018 8:33:47 PM MDT Nathan S. via Digitalmars-d-
learn wrote:
> The below writes "uint". Is this working as intended?
> https://run.dlang.io/is/Dx2e7f
>
> ---
> import std.stdio;
>
> auto foo(T = uint)(uint x)
> {
>  return T.stringof;
> }
>
> auto foo(T = ulong)(ulong x)
> {
>  return T.stringof;
> }
>
> void main()
> {
>  writeln(foo(10L));
> }
> ---

Probably, though personally, I'm inclined to think that it should pick the
second. It's clearly using VRP to decide that 10L fits in a uint. If you
pick something like

 writeln(foo(99L));

then it will call the ulong overload. Either way, since a long is neither a
uint or a ulong, it has to pick which overload it thinks is better. It would
seem to me that ulong would be closer (and if VRP weren't involved, it would
pick the ulong overload), but given that it knows what the value is, it
knows that either can work.

Unfortunately, searching through the spec, I don't see anything in it
mentioning either VRP or Value Range Propagation, so it doesn't look like
the correct behavior is actually spec-ed out. It could be that it works the
way it does in this case because of an intentional choice, or it could just
be the consequence of logic choices that make sense in other contexts but
not so much here. Personally, I would argue that VRP shouldn't come into
play if it's not necessary, but I don't know what the actual rules for it
are.

I suggest that you report this as a potential bug. At minimum, the spec
needs to be updated with the rules for VRP.

- Jonathan M Davis





Re: Mutable ForwardRange save() method not callable using const object

2018-09-04 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, September 4, 2018 9:22:26 AM MDT Timoses via Digitalmars-d-learn 
wrote:
> On Tuesday, 4 September 2018 at 14:26:44 UTC, Steven
>
> Schveighoffer wrote:
> > [...]
> > As general advice, I wouldn't expect const to work well with
> > Ranges anyway -- const ranges are useless (you can't iterate
> > them). So not much code is expecting to handle const, including
> > the wrappers that Phobos provides.
>
> Thanks, that sounds like some good advice. I've actually bumped
> into this right after when I had an immutable range which was
> supposed to fill in its cache when being iterated.
> My argument for why this should work is that "from the outside of
> the range" it is immutable, since accessing via opIndex will
> always give the same value.
> ... In the end, that'll lead nowhere. The immutable attribute
> would become a "promise" rather than an enforcement (or too hard
> for the compiler to enforce).

That's simply not how const or immutable work in D though. They're actual
compiler guarantees, and it's undefined behavior to ever cast away const or
immutable and mutate the object. D's const is fundamentally different from
C++'s const in this regard. Not only is a const that doesn't provide
compiler guarantees useless according to Walter (though that's obviously
debatable), but the nature of immutable pretty much requires it. immutable
objects are implicitly shared, and in principle, they could end up in ROM.
So, even if your object is const, there's no guarantee that it's actually
mutable underneath the hood. The rigidness of D's const and immutable are
both a blessing and a curse. But the net result is we really can't have a
range API that works with them without more of a head/tail model (whereas
the current API mutates in place), and even if we had a head/tail model, it
would still get pretty hairy thanks to issues like reference counting.

So, as Steven points out, const and ranges don't go together at all. The
result is that a number of us use stuff like const and inout pretty
sparingly (at least outside of primitive types):

http://jmdavisprog.com/articles/why-const-sucks.html

- Jonathan M Davis





Re: Can passing an address of this to a non-copyable object be made trusted? - i.e. can I disable moving?

2018-08-26 Thread Jonathan M Davis via Digitalmars-d-learn
On Sunday, August 26, 2018 5:10:29 PM MDT Nicholas Wilson via Digitalmars-d-
learn wrote:
> On Sunday, 26 August 2018 at 20:17:30 UTC, aliak wrote:
> > So if we had this:
> >
> > struct A(T) {
> >
> >   auto proxy() @trusted {
> >
> > return B!T();
> >
> >   }
> >
> > }
> >
> > struct B(T) {
> >
> >   private A!T* source;
> >   private this(A!T* s) { source = s; }
> >   @disable this();
> >   @disable this(this) {}
> >   @disable void opAssign(B!T);
> >
> > }
> >
> > In order for f to be "safe" I need to ensure that B!T()
> > does not escape the scope of A!T. I figured disable
> > construction and copying may work, but it seems you can still
> > get it moved:
> >
> > void main() @safe {
> >
> >   auto f() {
> >
> > auto a = A!int();
> > return a.proxy;
> >
> >   }
> >   auto escaped = f; // escaped.source is gone...
> >
> > }
> >
> > Anyway around this?
> >
> > Cheers,
> > - Ali
>
> Not sure abut the current language but DIP1014
> https://github.com/dlang/DIPs/blob/master/DIPs/DIP1014.md#final-review
>
> "The point was made that allowing opPostMove to be overidden
> raises the question of what to do when it is annotated with
> @disable. The concensus was that, in such a case, an actual
> attempt to move the object would result in a compilation error."
>
> So, soon™?

Yeah. Hopefully, we're able to disable moving at some point in the near
future. However, right now, it's definitely not possible. So, if you have a
type where it won't work properly if it's ever moved, then either you need
to rethink what you're doing, or you must be _very_ careful with how you use
any object of that type so that you don't ever use it in a way that even
might result in it being moved.

- Jonathan M Davis






Re: Clock.currTime differs from SysTime

2018-08-25 Thread Jonathan M Davis via Digitalmars-d-learn
On Saturday, August 25, 2018 6:53:24 AM MDT Ivo via Digitalmars-d-learn 
wrote:
> I am using Clock.currTime.stdTime to get a unique timestamp in my
> program.
> Now I need to produce something similar in a different
> programming language; so I'm trying to understand how
> Clock.currTime works.
>
> According the the documentation Clock.currTime.stdTime should
> return the number of hnseconds since 00:00 of 01/01/0001 A.D.
> UTC. However it seems that it returns less than what claimed.
>
> Consider the following code:
>
> import std.stdio;
> import std.datetime.date : DateTime;
> import std.datetime.timezone : UTC;
> import std.datetime.systime;
>
> void main() {
>
> auto now = Clock.currTime;
> auto date = DateTime(2018, 8, 25, 14, 42, 0); //this is changed
> manually
> auto st = SysTime(date, UTC());
> writeln(st.stdTime);
> writeln(st.toISOExtString);
> writeln(now.stdTime);
> writeln(now.toISOExtString);
>
> }
>
> I'm done a few tries and here is an output:
> 6367080492 //this is st.stdTime
> 2018-08-25T14:42:00Z
> 636707977205129550 //this is now.stdTime
> 2018-08-25T14:42:00.512955
>
> So here is the problem: the difference in time is less than 0.6
> seconds (according to the strings), nevertheless the difference
> of the 2 numbers is 71994870450.
> 71994870450 hnsecs = 71994870450 x 10^{-7} secs = 7199,487045
> secs (unless my maths is wrong)
>
> So what actually is Clock.currTime.stdTime counting?

By default, Clock.currTime returns a SysTime with LocalTime as the TimeZone.
stdTime is always in UTC. So, now's TimeZone is LocalTime, and when you
print it out as a string, you get the date and time in your local time zone
(which you can tell by the lack of time zone information on the end of the
string), whereas when you then construct a SysTime using the same date and
time as your local time zone but tell it that it's in UTC, then the two
values are going to be off by the offset between your local time zone and
UTC - and of course, casting to DateTime strips off the fractional seconds.

If you want to cast a SysTime to DateTime and then construct a SysTime from
it again, then you need to construct the SysTime with the same TimeZone, or
they won't be the same.

And sadly, even if you _do_ do that, and the time was right on the second
(so that there are no fractional seconds), they _still_ might not be the
same if the date and time are near a DST switch. Even though it _usually_
works to convert between a time zone and UTC, in the general case, it's
impossible - with some DST switches you get times that are completely
skipped and thus technically aren't valid, whereas at other DST switches,
you have times that happen twice, resulting in ambiguity. That's why SysTime
always holds the time internally in UTC rather than in whatever time zone
it's set to. The TimeZone object is just used when a function on SysTime
requires that it be converted out of UTC (e.g. when printing out a string or
using a property like year). Unfortunately, that still leaves a problem of
what to do when constructing a SysTime from date and time during a DST
switch, and SysTime does it's best, but unfortunately, trying to convert
from a time zone to UTC is inherently a buggy process.

In this particular case, DST almost certainly was not a factor, but you
still ran into problems, because you used a different time zone when
constructing the new object. So, while it's certainly sometimes necessary to
construct a SysTime from a DateTime (or separate numbers), it's almost
always better to leave the result of Clock.currTime as a SysTime rather than
doing something like casting to DateTime and then constructing another
SysTime from it. Done "correctly," it will work most of the time, but you'll
still be screwed around DST switches.

- Jonathan M Davis





<    1   2   3   4   5   6   7   8   9   10   >