Re: Create array from range

2021-10-09 Thread H. S. Teoh via Digitalmars-d-learn
On Sat, Oct 09, 2021 at 11:58:14PM +, Greg Strong via Digitalmars-d-learn 
wrote:
> This should be a simple question, but I'm having difficult finding an
> answer.  How do I filter some elements of an array into a new array?
> The filter! function returns a range, but I can't seems to assign it
> to a new array.  I get:
> 
> Cannot implicitly convert expression of type FilterResult!(__lambda10 ...
> 
> Nothing I try to construct a new array seems to work.

You can use the .array function (from std.array) to create an array out
of the filtered range:

--
int[] myArray = [ ... ];
int[] filteredArray = myArray.filter!(e => ...).array;
--


T

-- 
Chance favours the prepared mind. -- Louis Pasteur


Re: Managing malloced memory

2021-10-06 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Oct 06, 2021 at 06:06:38PM +, anon via Digitalmars-d-learn wrote:
> I interface to a C library that gives me a malloced object. How can I manage
> that pointer so that it gets freed automatically.
> What I've thought of so far:
[...]
> * struct wrapped in automem/ refcounted: The struct still leaves
> original scope and calls the destructor

Why is it a problem that it calls the dtor?  I thought the whole point
of refcounting is for the dtor to decrement the refcount, and free the
malloc'd object only when the refcount has actually reached 0.

You do have to be careful about copy ctors, assignment operators, and
such, though, to make sure the refcount stays consistent throughout. And
the refcount should probably be on the heap somewhere (either GC heap or
part of the malloc'd object); you would not want a struct's by-value
semantics to make another copy of the refcount and end up freeing the C
object more than once.


T

-- 
Life is unfair. Ask too much from it, and it may decide you don't deserve what 
you have now either.


Re: Sort bug / strangeness

2021-10-01 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Oct 01, 2021 at 06:30:48PM +, Danny Arends via Digitalmars-d-learn 
wrote:
[...]
> Is there a sort() algorithm that avoids swapping the items themselves
> and e.g. just returns the indexes so I can reorder the original array
> myself ?

https://dlang.org/phobos/std_algorithm_sorting.html#.makeIndex


T

-- 
Caffeine underflow. Brain dumped.


Re: Program crash: GC destroys an object unexpectedly

2021-09-21 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Sep 21, 2021 at 08:36:49PM +, eugene via Digitalmars-d-learn wrote:
> On Tuesday, 21 September 2021 at 20:17:15 UTC, eugene wrote:
> 
> > Now, change operation order in the main like this:
> 
> Actually, all proposed 'fixes'
> 
> - use stopper somehow in the end (writeln(stopper.sg0.number))
> - change operation order
> - etc
> 
> are strange. I mean it's strange (for me) that these
> fixes make garbage collector behave as needed.

It's not strange.  You're seeing these problems because you failed to
inform the GC about the dependency between Main and stopper. So it's
free to assume that these are two independent, unrelated objects, and
therefore it can collect either one as soon as there are no more
references to it.

And since stopper isn't used anymore after declaration, an optimizing
compiler is free to assume that it's not needed afterwards, so it's not
obligated to keep the reference alive until the end of the function.

Since in actually there *is* a dependency between these objects, the
most "correct" solution is to include a reference to stopper somewhere
in Main. Then the GC would be guaranteed never to collect stopper before
Main becomes unreferenced.


T

-- 
Век живи - век учись. А дураком помрёшь.


Re: Program crash: GC destroys an object unexpectedly

2021-09-21 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Sep 21, 2021 at 08:17:15PM +, eugene via Digitalmars-d-learn wrote:
[...]
> ```d
> void main(string[] args) {
> 
> auto Main = new Main();
> Main.run();
> 
> auto stopper = new Stopper();
> stopper.run();
> ```
[...]
> ```d
> void main(string[] args) {
> 
> auto Main = new Main();
> auto stopper = new Stopper();
> 
> Main.run();
> stopper.run();
> ```
[...]
> Everything is Ok now, stopper is not collected soon after start.
> So the question is how this innocent looking change can affect GC
> behavior so much?...

In the first example, the compiler sees that the lifetime of Main is
disjoint from the lifetime of stopper, so it's free to reuse the same
stack space (or register(s)) to store both variables. (This is a pretty
standard optimization FYI.) So the line `auto stopper = new Stopper();`
would overwrite the reference to Main, and the GC would see Main as an
unreferenced object and may collect it at any point after the line
`Main.run();`.

In the second case, since the lifetimes of Main and stopper overlap, the
compiler (probably) conservatively assumes that their lifetimes last
until the end of the function, and so reserves disjoint places for them
on the stack.  This does not mean you're 100% safe, however. A
sufficiently optimizing compiler may determine that since Main and
stopper are independent, it is free to reorder the code such that the
two lifetimes are independent, and therefore end up with the same
situation as the first example.

If Main really depends on the existence of stopper, I'd argue that it
really should store a reference to stopper somewhere, so that as long as
Main is not unreferenced the GC would not collect stopper.


T

-- 
What's an anagram of "BANACH-TARSKI"?  BANACH-TARSKI BANACH-TARSKI.


Re: Program crash: GC destroys an object unexpectedly

2021-09-21 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Sep 21, 2021 at 07:42:48PM +, jfondren via Digitalmars-d-learn 
wrote:
> On Monday, 13 September 2021 at 17:18:30 UTC, eugene wrote:
> > I do not understand at all why GC considers those sg0 and sg1 as
> > unreferenced.
> > And why old gdc (without -Os) and old ldc do not.
> 
> Conclusion:
> 
> There's nothing special about sg0 and sg1, except that they're part of
> Stopper. The Stopper in main() is collected before the end of main()
> because it's not used later in the function and because there are
> apparently no other references to it that the GC can find (because the
> only reference is hidden inside the Linux epoll API).

Quick and dirty workaround: keep references to those objects in static
variables to prevent GC collection:

auto myFunc(...) {
static MyType* dontCollect = null;

MyType* obj = new MyObject(...);
dontCollect = obj;
scope(exit) dontCollect = null; // may collect after function 
exits

... // function body goes here
}


T

-- 
Verbing weirds language. -- Calvin (& Hobbes)


Re: Which operators cannot be overloaded and why not?

2021-09-14 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Sep 13, 2021 at 06:19:20PM +, NonNull via Digitalmars-d-learn wrote:
> On Monday, 13 September 2021 at 16:12:34 UTC, H. S. Teoh wrote:
> > On Mon, Sep 13, 2021 at 02:12:36PM +, NonNull via
> > Digitalmars-d-learn wrote:
> > > Which operators cannot be overloaded and why not?
> > 
> > Others have already given the list, so I won't repeat that.
> 
> I didn't see unary &. Maybe others are missing.
[...]

IIRC, unary & cannot be overloaded for the same reasons &&, ||, and !
cannot be overloaded: it leads to hard-to-understand, hard-to-maintain
code.  Incidentally, C++ *does* allow overloading of &, ostensibly
because some wrapper types might want to use it to become transparent.
But one of the consequences of this is that now you need a
std::address-of pseudo-operator that *actually* takes an address of
something when you *really* mean to take the address of the wrapper
object instead of the wrapped object.  So & loses its original meaning
and has to be replaced by a std:: hack.  Which, to me, is abundant proof
that overloading & was a bad idea in the first place.

//

BTW, as an aside, as a example of why every-man-for-himself,
wild-wild-west operator overloading in C++ is a bad idea, consider these
two lines of C++ code:

fun(a, b);
gun(a, b);

What do they mean?  Ostensibly, these are function calls to two template
functions, specifying explicit template arguments.  Unfortunately, that
is not the case: only *one* of these lines is a template function call,
the other is something else altogether.  But nobody can tell the
difference unless they read the entire context, as shown below.
(Incidentally, this example also shows why C++'s choice of template
syntax was a poor one.) Compile and run with a C++ compiler to find out
what the actual behaviour is.


---
// Totally evil example of why C++ template syntax and free-for-all
// operator overloading is a Bad, Bad Idea.
#include 

struct Bad { };
struct B { };
struct A {
Bad operator,(B b) { return Bad(); }
};
struct D { };
struct Ugly {
D operator>(Bad b) { return D(); }
} U;
struct Terrible { } T;
struct Evil {
~Evil() {
std::cout << "Hard drive reformatted." << std::endl;
}
};
struct Nasty {
Evil operator,(D d) { return Evil(); }
};
struct Idea {
void operator()(A a, B b) {
std::cout << "Good idea, data saved." << std::endl;
}
Nasty operator<(Terrible t) { return Nasty(); }
} gun;

template
void fun(A a, B b) {
std::cout << "Have fun!" << std::endl;
}

int main() {
A a;
B b;

// What do these lines do?
fun(a, b);
gun(a, b);
}
---


T

-- 
Your inconsistency is the only consistent thing about you! -- KD


Re: Which operators cannot be overloaded and why not?

2021-09-13 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Sep 13, 2021 at 02:12:36PM +, NonNull via Digitalmars-d-learn wrote:
> Which operators cannot be overloaded and why not?

Others have already given the list, so I won't repeat that. As to the
"why":

In general, D tries to avoid the wild wild west, every operator for
himself situation in C++ that leads to unreadable, unmaintainable code.

For example, C++ allows you to separately overload <, <=, ==, >, >=, !=.
That means the programmer is free to define == and != in a way
completely inconsistent with each other, for example.  D solves this by
combining == and != into a single operator overload, opEquals, where !=
is the negation of ==. This ensures == and != are always consistent with
each other.  Same with <, <=, >, >=: C++ lets you overload each one
separately, potentially in a completely inconsistent way with each
other, so that somebody reading your code has no idea whether x < y
implies y >= x, or whether x < y implies y > x. Again, unreadable code.
D solves this by combining all these operators into a single overload:
opCmp.  This ensures consistency between all of these relative
comparison operators.

Similarly, prefix ++/-- and postfix ++/-- cannot be separately
overloaded; they are combined into a single overload, where postfix
++/--, as in `x++`, is simply rewritten by the compiler to the
equivalent of:

(){ auto tmp = x; x++; return tmp; }()

(Of course, this is just to illustrate the semantics. The compiler
doesn't actually create a lambda here.)

This ensures that prefix and postfix operators behave in the expected
way, so that ++x and x++ don't behave in two wildly different, unrelated
ways, like it sometimes happens in C++ code because C++ lets you define
separate overloads for them.

Combining these operator overloads have the additional benefit that less
overloads are needed to implement a numerical type: instead of needing
to separately implement ==, !=, <, <=, >, >=, you only have to implement
two overloads, opEquals and opCmp, and the compiler takes care of the
rest. Similarly, ++ and -- only need to be implement once each, and
you'll get the postfix varieties for free.

Furthermore, the boolean operators !, &&, || are not directly
overloadable. Again, C++ lets you separately overload them, which
guarantees that when you see (what looks like) a boolean expression in
C++, you have no idea what its true semantics are, because && could mean
something completely different from the usual meaning.  D doesn't let
you overload these operators, thereby ensuring that a boolean expression
remains a boolean expression: !, &&, || always have the standard
semantics.  What D *does* let you do is to define opCast!bool yourself,
so that you can define how a user-defined type converts to a bool, which
can then participate in the !, &&, || operators in the usual way.


In general, the philosophy in D is that operator overloading really
should be reserved for number-like (or math-like) objects, and
overloaded operators are expected to behave more-or-less like their
standard, non-overloaded meanings. Operator overloading of the variety
that C++ likes to do, like iostream's <<, >> overloads, are frowned
upon, because they obscure the surface meaning of the code and make it
hard to understand and maintain. (Incidentally, D *does* allow you to
overload '<<' and '>>'. It's just frowned upon to overload them in a way
that doesn't in someway represent bit-shifting.)  Furthermore,
overloaded operators are expected to behave analogously w.r.t. each
other, e.g., == and != should behave like opposites of each other; <
should not have completely unrelated semantics to >, and so on.


T

-- 
The right half of the brain controls the left half of the body. This means that 
only left-handed people are in their right mind. -- Manoj Srivastava


Re: Proper way to accept either static or dynamic array as a parameter

2021-09-11 Thread H. S. Teoh via Digitalmars-d-learn
On Sun, Sep 12, 2021 at 01:08:17AM +, Alex Bryan via Digitalmars-d-learn 
wrote:
> I am having trouble discovering what the proper (or at least a proper)
> way is to write a function that can take either a static or dynamic
> array as a parameter. My current implementation consists of 2
> overloaded functions (one takes a dynamic array, the other takes a
> static array) with 99% copy/pasted code. My intuition tells me this is
> dirty, and there's a better way to do this with templates, but for the
> life of me I just can't figure it out.  Would someone be so kind as to
> please help me out?
[...]

Just make the function take an array parameter. Static arrays will decay
into a slice (though my recommendation is to explicitly slice it with
the [] operator):

auto myFunction(T[] data) { ... }

T[10] staticArr;
T[] dynArr = [ ... ];

myFunction(staticArr);  // implicit slice, not recommended
myFunction(staticArr[]);// explicit slice, better
myFunction(dynArr);


T

-- 
Life is too short to run proprietary software. -- Bdale Garbee


Re: Phobos Unittest

2021-09-03 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Sep 03, 2021 at 11:39:44PM +, Per Nordlöw via Digitalmars-d-learn 
wrote:
> When is a phobos unittest supposed to be qualified with version
> `(StdUnittest)`? Ideally, always? I don't see that their current use
> is consistenly following a rule. If so, is the purpose of its presence
> to reduce the burden of the compiler when the application using phobos
> is compiled with -unittest? (edited).
[...]

This is related to the bogonity of the current behaviour of -unittest,
which compiles *all* unittests of *all* imported modules, even when
you're compiling user code that has no interest in Phobos unittests.
StdUnittest is a hack introduced to suppress Phobos unittests in user
programs.  Theoretically it's supposed to apply to all unittests, but
obviously whoever did it failed to cover every case.

It's still up in the air whether or not this should even be fixed.
Ideally, we should be fixing the behaviour of -unittest instead of
living with this hack.


T

-- 
I'm still trying to find a pun for "punishment"...


Re: template parameters

2021-09-02 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Sep 02, 2021 at 02:28:23PM -0700, Charles Hixson via 
Digitalmars-d-learn wrote:
[...]
> -- 
> Javascript is what you use to allow third part programs you don't know
> anything about and doing you know not what to run on your computer.

ROFL!  I'm st^Wborrowing this for my quotes file. ;-)


T

-- 
"How are you doing?" "Doing what?"


Re: Run-time setting of immutable variable?

2021-09-02 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Sep 02, 2021 at 05:17:15PM +, DLearner via Digitalmars-d-learn 
wrote:
[...]
> The following clean-compiled and produced the expected result:
> ```
> ubyte[10] Arr;
> 
> immutable void* ArrPtr;
>   shared static this() {
>   ArrPtr = cast(immutable void*)([0]);
>   }

Casting this to immutable is unsafe, because Arr is actually mutable. In
D, const and immutable are transitive, so when you cast a pointer into
immutable, you're basically promising that *both* the pointer *and* the
data pointed to will never change. The compiler is free to assume that
the data pointed to will never change, which may cause consistency
problems if the data *does* change later.

In cases like this, const is a better choice: const ensures that the
pointer will not mutate and the pointed-to data cannot be mutated
through this pointer, but the data *may* be mutated through another
reference (e.g., by modifying Arr directly).


[...]
> I am looking for a mutable Arr but would like an immutable ArrPtr.

In D, const and immutable are transitive, so you cannot do this (but see
below).


> ```
> `Arr` is not immutable, so `ArrPtr` shouldn't point at it if it's
> immutable.
> ```
> Surely there is no inconsistency - at run time the array is in a fixed
> place,  so ArrPtr is (or at least should be) a constant, but the
> contents of the array can vary as the program runs.

In this case, what you want is const, not immutable.  Const means you
cannot modify the pointer, and you cannot mutate the data through this
pointer, but you *can* modify the array from a mutable reference.


T

-- 
You are only young once, but you can stay immature indefinitely. -- azephrahel


Re: Run-time setting of immutable variable?

2021-09-02 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Sep 02, 2021 at 04:01:19PM +, DLearner via Digitalmars-d-learn 
wrote:
> Suppose there is a variable that is set once per run, and is
> (supposed) never to be altered again.  However, the value to which it
> is set is not known at compile time.

This is the classic use case of `immutable`.  Using the example you
gave, you'd move the initialization of ArrPtr into a static module
constructor:

immutable void* ArrPtr;
shared static this() {
ArrPtr = ...; // initialize it here
}

void main() {
... // ArrPtr is immutable from here on.
}


T

-- 
Дерево держится корнями, а человек - друзьями.


Re: Question on Immutability

2021-08-30 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Aug 30, 2021 at 11:27:07PM +, Merlin Diavova via 
Digitalmars-d-learn wrote:
> Hi All,
> 
> I'm trying to understand immutability in D and it seems a bit odd.
> I'm coming from dynamic languages so please forgive my ignorance and
> dynamic language-isms.
> 
> I want to have a base `Project interface` and then extend other more
> specific interfaces from that such as `DockerEnabledProject
> interface`, `NetworkEnabledProject interface` etc.
> 
> The interface implementations are immutable. I have defined some
> methods that allows one to change specific properties and return a new
> instance of the implementation.

> 
> ```d
> immutable interface Project
> {
> string name();
> immutable(Project) withName(string name); // Returns a new instance
> }
> 
> immutable class ShellScriptCLI : Project
> {
> private string _name, _slug;
> private DirectoryPath _directory;
> 
> string name()
> {
> return this._name;
> }
> 
> immutable(Project) withName(string name)
> {
> return new immutable ShellScriptCLI(name, this._slug,
> this._directory);
> }
> }
> 
> ...
> 
> auto project = new immutable ShellScriptCLI("Project One", "project-one",
> projectPath);
> auto modifiedProject = project.withName("G2 Project");
> assert(modifiedProject.name == "G2 Project");
> ```
> After playing around the above works, Great! However I have some questions
> 
> First, why do the interfaces have to be defined as `immutable interface`?
> The interfaces cannot be changed at runtime or instantiated.
>
> Secondly, why does defining the return type for withName as `Project`
> give the `Error: 'immutable' method 'winry.project.Project.name' is
> not callable using a mutable object`. However changing it to
> `immutable(Project)` works as expected.

You need to declare Project.name and Project.withName with either
`const` or `immutable`, like this:

 string name() const;
 immutable(Project) withName(string name) immutable;

The second `immutable` in .withName applies to the implicit `this`
parameter received by every method.  Without this qualifier you cannot
invoke it with an immutable object.

The interface itself does not need to be immutable; putting `immutable`
on it merely makes `immutable` the default attributes in member
declarations, which is likely not what you want if you will be defining
mutable data fields later on.  It happens to fix your compile error
because you forgot to put `const` or `immutable` on .name and .withName.

//

The best way to understand const/mutable/immutable in D is this little
diagram (forgive the ASCII art):

   const
  / \
mutable immutable

Think of it as analogous to a class hierarchy diagram (a "type
hierarchy" if you will): both mutable and immutable implicit convert to
const, but const does not convert to either.

Basically, `const` means the holder of the reference is not allowed to
modify it.  So it doesn't matter whether the original data was mutable
or immutable: as far as the recipient is concerned, it cannot modify the
data, so everything is good.

`immutable` means that ALL references to the data cannot modify it (this
applies across threads too).  Const data *could* be modified by somebody
who happens to hold a mutable reference to it; immutable data cannot be
modified, period.  This means immutable can be freely shared across
threads (there are no mutable references to it, so the data never
changes and any thread can read it without needing to synchronize).

Furthermore, const/immutable in D is transitive, i.e., if a reference is
const, then any data it references is also implicitly const, and the
data referenced by said data, etc., is also const. Ditto with immutable.
We call it "turtles all the way down". :-)  In D you cannot have an
immutable reference to immutable data, and if you have a const reference
to something, you cannot modify anything it may refer to recursively.


T

-- 
The most powerful one-line C program: #include "/dev/tty" -- IOCCC


Re: Interpolate dates

2021-08-30 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Aug 30, 2021 at 12:06:46AM +, Booster via Digitalmars-d-learn wrote:
> I have some dates and date-times. I need to interpolate the date-times
> from the dates.

Try looking at std.datetime perhaps?


T

-- 
The diminished 7th chord is the most flexible and fear-instilling chord. Use it 
often, use it unsparingly, to subdue your listeners into submission!


Re: Mixin/static if issue

2021-08-25 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Aug 25, 2021 at 10:16:39PM +, DLearner via Digitalmars-d-learn 
wrote:
> Please see below:
> ```
> void main() {
>import std.stdio;
> 
>uint TestVar = 5;
> 
>string mxnWrite_Size_t(string VarName) {
^^
Obviously, VarName is a string. Why would you expect anything else?


>   static if (typeof(VarName).stringof == "uint") {
[[...]

I think what you meant to write is:

   static if (typeof(mixin(VarName)).stringof == "uint") {

You want the type of the variable named by VarName, not the type of
VarName.


T

-- 
Many open minds should be closed for repairs. -- K5 user


Re: foreach() behavior on ranges

2021-08-25 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Aug 25, 2021 at 04:46:54PM +, Joseph Rushton Wakeling via 
Digitalmars-d-learn wrote:
> On Wednesday, 25 August 2021 at 10:59:44 UTC, Steven Schveighoffer wrote:
> > structs still provide a mechanism (postblit/copy ctor) to properly
> > save a forward range when copying, even if the guts need copying
> > (unlike classes). In general, I think it was a mistake to use
> > `.save` as the mechanism, as generally `.save` is equivalent to
> > copying, so nobody does it, and code works fine for most ranges.
> 
> Consider a struct whose internal fields are just a pointer to its
> "true" internal state.  Does one have any right to assume that the
> postblit/copy ctor would necessarily deep-copy that?
[...]
> If that struct implements a forward range, though, and that pointed-to
> state is mutated by iteration of the range, then it would be
> reasonable to assume that the `save` method MUST deep-copy it, because
> otherwise the forward-range property would not be respected.
[...]

What I understand from what Andrei has said in the past, is that a range
is merely a "view" into some underlying storage; it is not responsible
for the contents of that storage.  My interpretation of this is that
.save will only save the *position* of the range, but it will not save
the contents it points to, so it will not (should not) deep-copy.

However, if the range is implemented by a struct that contains a
reference to its iteration state, then yes, to satisfy the definition of
.save it should deep-copy this state.


> With that in mind, I am not sure it's reasonable to assume that just
> because a struct implements a forward-range API, that copying the
> struct instance is necessarily the same as saving the range.
[...]

Andrei has mentioned before that in retrospect, .save was a design
mistake.  The difference between an input range and a forward range
should have been keyed on whether the range type has reference semantics
(input range) or by-value semantics (forward range).  But for various
reasons, including the state of the language at the time the range API
was designed, the .save route was chosen, and we're stuck with it unless
Phobos 2.0 comes into existence.

Either way, though, the semantics of a forward range pretty much
dictates that whatever type a range has, if it claims to be a forward
range then .save must preserve whatever iteration state it has at that
point in time. If this requires deep-copying some state referenced from
a struct, then that's what it takes to satisfy the API.  This may take
the form of a .save method that copies state, or a copy ctor that does
the same, or simply storing iteration state as PODs in the range struct
so that copying the struct equates to preserving the iteration state.


T

-- 
Why waste time reinventing the wheel, when you could be reinventing the engine? 
-- Damian Conway


Re: foreach() behavior on ranges

2021-08-24 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Aug 24, 2021 at 08:36:18AM +, frame via Digitalmars-d-learn wrote:
> Consider a simple input range that can be iterated with empty(),
> front() and popFront(). That is comfortable to use with foreach() but
> what if the foreach loop will be cancelled? If a range isn't depleted
> yet and continued it will supply the same data twice on front() in the
> next use of foreach().

Generally, if you need precise control over range state between multiple
loops, you really should think about using a while loop instead of a for
loop, and call .popFront where it's needed.


> For some reason, foreach() does not call popFront() on a break or continue
> statement. There is no way to detect it except the range itself tracks its
> status and does an implicit popFront() if needed - but then this whole
> interface is some kind of useless.

In some cases, you *want* to retain the same element between loops,
e.g., if you're iterating over elements of some category and stop when
you encounter something that belongs to the next category -- you
wouldn't want to consume that element, but leave it to the next loop to
consume it.  So it's not a good idea to have break call .popFront
automatically.  Similarly, sometimes you might want to reuse an element
(e.g., the loop body detects a condition that warrants retrying).

Basically, once you need anything more than a single sequential
iteration over a range, it's better to be explicit about what exactly
you want, rather than depend on implicit semantics, which may lead to
surprising results.

while (!range.empty) {
doSomething(range.front);
if (someCondition) {
range.popFront;
break;
} else if (someOtherCondition) {
// Don't consume current element
break;
} else if (skipElement) {
range.popFront;
continue;
} else if (retryElement) {
continue;
}
range.popFront; // normal iteration
}


T

-- 
"No, John.  I want formats that are actually useful, rather than
over-featured megaliths that address all questions by piling on
ridiculous internal links in forms which are hideously over-complex." --
Simon St. Laurent on xml-dev


Re: simple (I think) eponymous template question ... what is proper idimatic way ?

2021-08-17 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Aug 17, 2021 at 07:53:52PM +, james.p.leblanc via 
Digitalmars-d-learn wrote:
> On Tuesday, 17 August 2021 at 19:44:29 UTC, H. S. Teoh wrote:
> > You could use a helper template and an AliasSeq for this:
> > 
> > template isAmong(T, S...) {
> > static if (S.length == 0)
> > enum isAmong = false;
> > else
> > enum isAmong = is(T == S) ||
> > isAmong(T, S[1..$]);
> > }
> > 
> > import std.meta : AliasSeq;
> > alias MyTypes = AliasSeq!(int, float, MySpecialStruct);
> > 
> > auto myFunc(T)(T a, T b) if (isAmong!(T, MyTypes)) { ... }
[...]
> Dear H.S. Teoh,
> 
> Wow!  That is absolutely beautiful ... I had never seen (or even
> imagined) a recursive template!  This expands my mind in a good
> way ... and is going into my toolbox immediately.
[...]

I didn't want to spoil your joy of discovery, but since others have
already done that -- beware of recursive templates, because if used too
often they can become a source of big slowdowns to your compilation
times (as well as the compiler consuming ridiculous amounts of memory).

Simple, linearly-recursive templates like this one are probably harmless
(unless you artificially generate pathologically-long lists of types).
But if the recursion gets too deep or grows superlinearly, you probably
want to consider alternative implementations instead. ;-)


--T


Re: simple (I think) eponymous template question ... what is proper idimatic way ?

2021-08-17 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Aug 17, 2021 at 07:22:54PM +, james.p.leblanc via 
Digitalmars-d-learn wrote:
[...]
> auto moo(T : (int || float || mySpecialStruct )(T myMoo) {•••}
> 
> When re-using any such sets, it would be nice to define the set as
> follows:
> 
> S = (int || float || mySpecialStruct)
> 
> and then define "moo" more concisely as:
> 
> auto moo(T < S)(T myMoo) {•••}
> 
> ( where I have used "<" to mean "T is a member of S").
[...]

You could use a helper template and an AliasSeq for this:

template isAmong(T, S...) {
static if (S.length == 0)
enum isAmong = false;
else
enum isAmong = is(T == S) ||
isAmong(T, S[1..$]);
}

import std.meta : AliasSeq;
alias MyTypes = AliasSeq!(int, float, MySpecialStruct);

auto myFunc(T)(T a, T b) if (isAmong!(T, MyTypes)) { ... }


T

-- 
I am a consultant. My job is to make your job redundant. -- Mr Tom


Re: simple (I think) eponymous template question ... what is proper idimatic way ?

2021-08-17 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Aug 17, 2021 at 06:11:56PM +, james.p.leblanc via 
Digitalmars-d-learn wrote:
> Evening All,
> 
> Eponymous templates allow a nice calling syntax.  For example, "foo"
> here can be called without needing the exclamation mark (!) at calling
> sites.  We see that foo is restricting a, and b to be of the same type
> ... so far, so good.
> 
> auto foo(T)(T a, T b) { ... }
> 
> Now, suppose I need to restrict "T" only certain subsets of variable
> types.

This is exactly what "signature constraints" are for.  For example:

auto foo(T)(T a, T b)
if (is(T == string)) // <--- this is a signature constraint
{
... // deal with strings here
}

auto foo(T)(T a, T b)
if (is(T == int)) // you can overload on signature constraints
{
... // deal with ints here
}

auto foo(T)(T a, T b)
if (is(T == float) || is(T == double)) // you can use complex conditions
{
... // deal with floats or doubles here
}

Be aware that a signature constraint failure is not an error: the
compiler simply skips that overload of the function.  So if you make a
mistake in a sig constraint, it may *always* fail, and the compiler may
try instead to instantiate a completely unintended overload and generate
an error that may have nothing to do with the actual problem.


T

-- 
Give a man a fish, and he eats once. Teach a man to fish, and he will sit 
forever.


Re: How to extend the string class to return this inside the square bracket?

2021-08-13 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Aug 13, 2021 at 04:35:54PM -0700, Ali Çehreli via Digitalmars-d-learn 
wrote:
> On 8/13/21 4:23 PM, Marcone wrote:
> 
> > string x = "Hello World!";
> > writeln(x[x.indexOf("e")..x.indexOf("r")]);
> 
> I don't see the usefulness and there are the following problems with
> it:
> 
> - Not an algorithmic complexity issue but it sounds to me like a
> pessimization to go through the elements in linear fashion, obtain
> indexes and then iterate between the indexes again.
[...]

In the above example, what all those indexOf calls really want to say
is, "give me a slice of x starting from the first occurrence of 'e' to
the next occurrence of 'r'".  Once this is understood, the rest follows:

writeln(x.find('e') // find first occurrence of 'e'
.until('r') // slice until next occurrence of 'r'
);

Or more concisely:

writeln(x.find('e').until('r'));

This iterates x only once, and also avoids the pathological case where
'r' appears before 'e', which in the original code would throw a
RangeError because it generates a slice of negative length.

//

OTOH, if the OP insists that he wants arbitrary expressions inside
[...], one way to do it is to overload opSlice and opIndex, then create
placeholder objects that abstractly refer to parts of a string that
opIndex then interprets. Something like this:

// Warning: untested code
struct Idx { dchar ch; }
struct SliceRange { size_t start, end; }

struct StringWrapper {
string impl;
alias impl this;

SliceRange opSlice(Idx i1, Idx i2) {
return SliceRange(impl.indexOf(i1.ch),
impl.indexOf(i2.ch));
// or whatever more efficient implementation you
// wish to use
}

auto opIndex(SliceRange sr) {
return StringWrapper(impl[sr.start, sr.end]);
}

// Don't forget to implement .opDollar, which I omit
// here for conciseness.
}

StringWrapper blah = "abcdefgh";
assert(blah[Idx('c') .. Idx('g')] == "cdefg");

Note that the above is incomplete; it's just a sketch of the concept. To
make it work for all cases, opSlice needs to handle if one or both of
the indices are integers, etc..  And Idx probably needs operator
overloading in order to support arbitrary expressions (it basically
amounts to an expression template or a runtime expression tree, if taken
to its logical conclusion).

Truth be told, though, this is killing an ant with a nuclear warhead.  Why not
just write `x.find('e').until('r')` instead. ;-)


T

-- 
Valentine's Day: an occasion for florists to reach into the wallets of nominal 
lovers in dire need of being reminded to profess their hypothetical love for 
their long-forgotten.


Re: Anyway to achieve the following

2021-08-13 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Aug 13, 2021 at 05:11:50PM +, Rekel via Digitalmars-d-learn wrote:
[...]
> For anyone more experienced with C, I'm not well known with references
> but are those semantically similar to the idea of using a type at a
> predefined location?

References are essentially pointers under the hood. The difference is
that at the language level they are treated as aliases to the original
variable, and are therefore guaranteed to be non-null.

Note that in D `ref` is not a type constructor but a storage qualifier,
so you cannot declare a reference variable, you can only get one if you
pass a variable to a function that takes it by ref.


T

-- 
Spaghetti code may be tangly, but lasagna code is just cheesy.


Re: nested templates using Complex! with slices, ... confused, I am!

2021-08-09 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Aug 09, 2021 at 06:35:56PM +, james.p.leblanc via 
Digitalmars-d-learn wrote:
[...]
> > **T[] foo_temp(Complex!T[])(T x, T y){
> >   auto r = [x, x];
> >   auto i = [y, y];
> >   auto z = [ Complex!T(x, y), Complex!T(x,y) ];
> >   return z;
> > }**

Your syntax is wrong; the declaration should be:

Complex!T[] foo_temp(T)(T x, T y) { ... }

Basically, you're parametrizing on T, and returning an array of a
Complex type built upon T.


T

-- 
Curiosity kills the cat. Moral: don't be the cat.


Re: Setting a hard limit on slice size, is this possible?

2021-08-06 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Aug 06, 2021 at 06:02:01PM +, james.p.leblanc via 
Digitalmars-d-learn wrote:
[...]
> However, do NOT feel stupid ... the motivation behind why
> I cannot use a standard int[your_max_length] (in other words,
> use a static array), is because I need to do a specified
> memory alignment (known at compile time) on my slice, or array.

I've never actually tried this myself, but have you looked into the
`align` keyword in the D spec?  I'm not 100% sure whether it can be
applied to static arrays (or arrays in general) but it might be worth a
look.


> I understand that neither a slice or an array is capable to doing
> an arbitrary memory alignment.  (But, perhaps I am wrong about this
> ...)
> 
> I believe structs can be aligned, but need to learn more about the
> speicific of that.

One thing that might help you is if you had a struct with the
appropriate align(...) declaration that wraps around your array
elements. Pretty sure that would guarantee the alignment of array
elements, which in turn should guarantee alignment of the array as a
whole.


T

-- 
It is the quality rather than the quantity that matters. -- Lucius Annaeus 
Seneca


Re: best/proper way to declare constants ?

2021-08-05 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Aug 05, 2021 at 04:53:38PM +, someone via Digitalmars-d-learn wrote:
[...]
> I already assumed that loading the data from file is a goner.
> 
> So this leaves me with two choices:
> 
> - keep the code as it is incurring higher-than expected
> compilation-time: this is solely used in a module to build classes, I
> guess pretty minimal usage, but I don't know where this app will
> eventually go so better get it right to begin with
> 
> - find a better alternative
[...]

I'd say if the performance hit isn't noticeably bad right now, don't
worry too much about it. You can always replace it later. One thing I
really like about D is how easily refactorable D code tends to be. If
you structure your code in a way that keeps separate concerns apart (and
D features like metaprogramming really help with this), replacing your
implementation choice with something else often turns out to be
surprisingly simple.

But if you expect to process very large data files at compile-time, I'd
say consider generating the classes via a utility D program that emits D
code as a separate step.  In one of my projects I have a whole bunch of
3D model files that I need to convert into a format more suitable for
use at runtime.  I eventually opted to do this as a separate step from
the main compilation: a helper utility to parse the files, massage the
data, then spit out a .d file with the right definitions (including
embedded array literals for binary data), then compile that into the
main program.  Since the data rarely changes, it's a waste of time to
keep regenerating it every time I recompile; keeping it as a separate
step means I only need to rerun the helper utility when the data
actually changes as opposed to every single time I change 1 line of
code.


T

-- 
Those who don't understand Unix are condemned to reinvent it, poorly.


Re: best/proper way to declare constants ?

2021-08-05 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Aug 05, 2021 at 03:09:13PM +, someone via Digitalmars-d-learn wrote:
> On Thursday, 5 August 2021 at 10:28:00 UTC, Steven Schveighoffer wrote:
> 
> > H.S. Teoh, I know you know better than this ;) None of this is
> > necessary, you just need `rtValue` for both runtime and CTFE (and
> > compile time parameters)!

Haha, I haven't used this particular feature of D recently, so probably
my memory is failing me. ;-)


> > Now, the original question is about *associative arrays*, which are
> > a different animal. Those, you actually have to initialize using a
> > static constructor, and does indeed need both an enum and a static
> > immutable, as CTFE currently does not understand runtime AAs. This
> > is a huge issue since you do need silly things like the `if(__ctfe)`
> > statement you wrote, and keep an enum handy for those cases which is
> > identical to the static immutable. We really need to fix this.
> 
> When you say "We really need to fix this" you mean that *eventually*
> associative-arrays will be available at compile-time ?
[...]

AA's are already available at compile-time.  You can define them in CTFE
and pass them around as template arguments.

What doesn't work is initializing global static immutable AA's with
literals. Currently, you need this workaround:

struct Data { /* whatever you want to store here */ }
static immutable Data[string] aa;
shared static this() {
aa = [
"abc": Data(...),
"def": Data(...),
// ... etc.
];
}

Unfortunately, this also means you can't access the value of `aa` at
compile-time. So you need a separate enum in order to access AA values
at compile-time.

Full runnable example:
---
enum ctValue = [
"abc": 123,
"def": 456,
];

static immutable int[string] rtValue;
shared static this() {
rtValue = ctValue;
}

// Compile-time operations
enum x = ctValue["abc"];
enum y = ctValue["def"];
static assert(x == 123 && y == 456);

// Runtime operations
void main() {
assert(rtValue["abc"] == 123);
assert(rtValue["def"] == 456);
}
---


T

-- 
My father told me I wasn't at all afraid of hard work. I could lie down right 
next to it and go to sleep. -- Walter Bright


Re: best/proper way to declare constants ?

2021-08-04 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Aug 05, 2021 at 01:39:42AM +, someone via Digitalmars-d-learn wrote:
[...]
> What happens in the following case ?
> 
> public immutable enum gudtLocations = [
>r"BUE"d : structureLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
>r"GRU"d : structureLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
>r"HHN"d : structureLocation(r"deu"d, r"Frankfurt am Main"d, r"CET"d),
>r"LHR"d : structureLocation(r"gbr"d, r"London"d, r"UTC"d),
>r"NYC"d : structureLocation(r"usa"d, r"New York"d, r"EST"d)
>];
> 
> This is something that I also need at compilation time.
[...]

If you need a constant array value both at compile-time and runtime, one
way to do it is to declare an enum that is used only by compile-time
code, and the same enum is used once to declare the runtime static
immutable.

Example:

enum ctValue = [ "my", "data", "here", ... ];

// Initialize this once with ctValue.
static immutable string[] rtValue = ctValue;

if (ctfe) {
// Compile-time: use ctValue
foreach (value; ctValue) {
...
}
} else {
// Runtime: use rtValue instead
foreach (value; rtValue) {
...
}
}

Just be sure you don't use ctValue during runtime, otherwise it will
incur an allocation per use.


T

-- 
What did the alien say to Schubert? "Take me to your lieder."


Re: best/proper way to declare constants ?

2021-08-04 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Aug 05, 2021 at 12:47:06AM +, someone via Digitalmars-d-learn wrote:
> What are the pros/cons of the following approaches ?

1) If the constant is a POD (int, float, etc.), use:

enum myValue = ...;

2) If the constant is a string or some other array:

static immutable string myString = "...";
static immutable Data[] myData = [ ... ];

Unless you have a specific reason to, avoid using `enum` with string and
array literals, because they will trigger a memory allocation *at every
single reference to them*, which is probably not what you want.

enum myArray = [ 1, 2, 3 ];
...
int[] data = myArray;   // allocates a new array
int[] data2 = myArray;  // allocates another array

// they are separate arrays with the same contents
assert(data !is data2);
assert(data == data2);

// allocates a temporary array, does the comparison, then
// discards the temporary
if (data == myArray) ...

foreach (i; 0 .. 10) {
int[] input = getUserInput(...);

// allocates a new array at every single loop iteration
if (input == myArray) { ... }
}

Don't do this. Use static immutable for arrays and strings, use enum
only for PODs.


T

-- 
It's amazing how careful choice of punctuation can leave you hanging:


Re: Is returning void functions inside void functions a feature or an artifact?

2021-08-02 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Aug 02, 2021 at 04:42:14PM +, Rekel via Digitalmars-d-learn wrote:
[...]
> Also slightly off topic, but when would one use an alias instead of a
> function/delegate? I haven't used aliases before.

When you want a compile-time binding that could potentially elide the
indirect function call to a delegate.

// This generates a specialized template instance with
// `callback` bound to the passed-in compile-time argument, for
// each call to `myFunc`.
auto myFunc(alias callback)(...) { ...  }

// This is a single common function that receives an opaque
// runtime delegate and binds it at runtime.
auto myFunc(int delegate(...) callback, ...) { ...  }


T

-- 
An elephant: A mouse built to government specifications. -- Robert Heinlein


Re: Is returning void functions inside void functions a feature or an artifact?

2021-08-02 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Aug 02, 2021 at 02:31:45PM +, Rekel via Digitalmars-d-learn wrote:
> I recently found one can return function calls to void functions,
> though I don't remember any documentation mentioning this even though
> it doesn't seem trivial.

This is intentional, in order to make it easier to write generic code
without always having to special-case functions that don't return
anything. E.g.:

auto myWrapper(alias func, Args...)(Args args) {
// Don't have to special case void return.
return func(args);
}

int hooray(int i) { return i+1; }
void boo(int j) { return; }

int z = myWrapper!hooray(1);
myWrapper!boo(2);

Otherwise you'd have to litter your code with redundant special cases:

auto myWrapper(alias func, Args...)(Args args) {
static if (is(ReturnType!func == void))
func(args);
else
return func(args); // same thing but different
}

Allowing `return func(args)` for void functions eliminates the need for
such special cases.


T

-- 
"640K ought to be enough" -- Bill G. (allegedly), 1984. "The Internet is not a 
primary goal for PC usage" -- Bill G., 1995. "Linux has no impact on 
Microsoft's strategy" -- Bill G., 1999.


Re: translate C struct char array into D

2021-07-30 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jul 30, 2021 at 03:41:32PM +, Tejas via Digitalmars-d-learn wrote:
> On Friday, 30 July 2021 at 14:40:17 UTC, Paul Backus wrote:
[...]
> > ```d
> > struct test1 {
> > // member variables...
> > 
> > char* data() {
> > return cast(char*) ( + 1);
> > }
> > }
> > ```
> > 
> > [1]: http://port70.net/~nsz/c/c99/n1256.html#6.7.2.1p16
> 
> B-but the performance penalty of having an extra level of indirection?
> Absolutely unacceptable!!

Premature optimization.

Any optimizer worth its salt would be able to inline such a trivial
function as .data above.  Check the output of LDC -O, for example.
(Don't talk to me about dmd, if you care about performance you'd use LDC
instead.)


T

-- 
This is a tpyo.


Re: Build time

2021-07-23 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jul 23, 2021 at 06:53:06PM +, JG via Digitalmars-d-learn wrote:
[...]
> The program I writing is around 3000 loc and recently I noticed a
> large slow down in compile time which after investigation seemed to be
> caused by my computer running out of memory. The compile was using
> more than 15GB memory.  I tried using lowmem and that did solve the
> memory problem but the compile still takes around 1 minute. Any
> suggestion on how to try and improve the build time. I am currently
> using dub.

3000 loc and 1 minute build time?  Sounds like you're using too many
nested templates / CTFE.


> Of course one could try to use fewer templates and less meta
> programming but that seems to defeat the purpose of using d.

I wouldn't say use fewer templates / less meta-programming.  But I'd say
look into how deeply nested templates are, and whether some templates
parameters may be unnecessary.  If you have recursive templates,
consider refactoring it so that it uses linear expansion instead.
Shallowly-nested templates generally don't run into performance
problems.

(Confession: I wrote the variadic version of cartesianProduct in
std.algorithm with recursive templates. It uses an exponential number of
template expansions, and so quickly brings the compiler to its knees
when you try to take 4 or more cartesian products in a row.  Eventually,
I refactored the most common case (no infinite ranges among its
arguments) to use a linear expansion with a nested loop instead.
Compile times improved by a HUGE margin.)

And avoid doing too much work in CTFE, which is known to be slow. But
not as slow as overly-deeply nested templates.

Another way is to have a separate build step for expanding the most
heavy templates, so that you only incur that heavy expansion once in a
while when you change the relevant code.  I had a Vibe.d project where
Diet templates slowed me down too much (they are super template-heavy),
so I split it into several different build targets with a separate link
step, so that when I'm not changing the Diet templates it doesn't slow
me down so much.  Dub unfortunately won't help you here (unless you use
subpackages -- but I doubt it will win much) -- I recommend using a
better build system like CMake or SCons. Dub's architecture simply does
not play well with staged compilation.

Alternatively, use a separate pre-compilation stage for generating code
(e.g., write a utility that emits D code that then gets compiled in a
subsequent step).  As much as I love D's compile-time capabilities,
there comes a time when it's simply more practical to just `writefln`
some D code snippets into a file and compile that into the main program,
instead of trying to tame the memory-guzzling beast that is the D
compiler.


T

-- 
I am Ohm of Borg. Resistance is voltage over current.


Re: Not allowed to globally overload operators?

2021-07-20 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jul 20, 2021 at 11:32:26AM -0700, Ali Çehreli via Digitalmars-d-learn 
wrote:
> On 7/19/21 11:20 PM, Tejas wrote:
> 
> > trying to create the spaceship operator of C++
> 
> Just to make sure, D's opCmp returns an int. That new C++ operator was
> added to provide the same semantics.
[...]

FYI, opCmp *may* return float, which may be useful sometimes for
implementing partial orders (return float.nan when two elements are
incomparable).


T

-- 
"Outlook not so good." That magic 8-ball knows everything! I'll ask about 
Exchange Server next. -- (Stolen from the net)


Re: Yet another parallel foreach + continue question

2021-07-19 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jul 20, 2021 at 02:39:58AM +, seany via Digitalmars-d-learn wrote:
> On Tuesday, 20 July 2021 at 02:31:14 UTC, H. S. Teoh wrote:
> > On Tue, Jul 20, 2021 at 01:07:22AM +, seany via Digitalmars-d-learn
> > wrote:
> > > On Tuesday, 20 July 2021 at 00:37:56 UTC, H. S. Teoh wrote:
> > > > [...]
> > > 
> > > Ok, therefore it means that, if at `j = 13 `i use a continue, then
> > > the thread where I had `10`... `20` as values of `j`, will only
> > > execute for `j = 10, 11, 12 ` and will not reach `14`or later ?
> > 
> > No, it will.
> > 
> > Since each iteration is running in parallel, the fact that one of
> > them terminated early should not affect the others.
[...]
> Even tho, the workunit specified 11 values to a single thread?

Logically speaking, the size of the work unit should not change the
semantics of the loop. That's just an implementation detail that should
not affect the semantics of the overall computation.  In order to
maintain consistency, loop iterations should not affect each other
(unless they deliberately do so, e.g., read/write from a shared variable
-- but parallel foreach itself should not introduce such a dependency).

I didn't check the implementation to verify this, but I'm pretty sure
`break`, `continue`, etc., in the parallel foreach body does not change
which iteration gets run or not.

Think of it this way: when you use a parallel foreach, what you're
essentially asking for is that, logically speaking, *all* loop
iterations start in parallel (even though in actual implementation that
doesn't actually happen unless you have as many CPUs as you have
iterations). Meaning that by the time a thread gets to the `continue` in
a particular iteration, *all* of the other iterations may already have
started executing.  So it doesn't make sense for any of them to get
interrupted just because this particular iteration executes a
`continue`.  Doing otherwise would introduce all sorts of weird
inconsistent semantics that are hard (if not impossible) to reason
about.

While I'm not 100% sure this is what the current parallel foreach
implementation actually does, I'm pretty sure that's the case. It
doesn't make sense to do it any other way.


T

-- 
Ph.D. = Permanent head Damage


Re: Yet another parallel foreach + continue question

2021-07-19 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jul 20, 2021 at 01:07:22AM +, seany via Digitalmars-d-learn wrote:
> On Tuesday, 20 July 2021 at 00:37:56 UTC, H. S. Teoh wrote:
> > On Tue, Jul 20, 2021 at 12:07:10AM +, seany via Digitalmars-d-learn
> > wrote:
> > > [...]
> > [...]
> > 
> > I didn't test this, but I'm pretty sure `continue` inside a parallel
> > foreach loop simply terminates that iteration early; I don't think
> > it will skip to the next iteration.
> > 
> > [...]
> 
> Ok, therefore it means that, if at `j = 13 `i use a continue, then the
> thread where I had `10`... `20` as values of `j`, will only execute
> for `j = 10, 11, 12 ` and will not reach `14`or later ?

No, it will.

Since each iteration is running in parallel, the fact that one of them
terminated early should not affect the others.


T

-- 
Skill without imagination is craftsmanship and gives us many useful objects 
such as wickerwork picnic baskets.  Imagination without skill gives us modern 
art. -- Tom Stoppard


Re: Yet another parallel foreach + continue question

2021-07-19 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jul 20, 2021 at 12:07:10AM +, seany via Digitalmars-d-learn wrote:
> Consider :
> 
> for (int i = 0; i < max_value_of_i; i++) {
> foreach ( j, dummyVar; myTaskPool.parallel(array_to_get_j_from,
> my_workunitSize) {
> 
> if ( boolean_function(i,j) ) continue;
> double d = expensiveFunction(i,j);
> // ... stuff ...
> }
> }
> 
> I understand, that the parallel iterator will pick lazily values of
> `j` (up to `my_workunitsize`), and execute the for loop for those
> values in its own thread.
> 
> Say, values of `j` from `10`to `20` is filled where `my_workunitsize`
> = 11.  Say, at `j = 13` the `boolean_function` returns true.
> 
> Will then the for loop just jump to the next value of `j = 14`  like a
> normal for loop? I am having a bit of difficulty to understand this.
[...]

I didn't test this, but I'm pretty sure `continue` inside a parallel
foreach loop simply terminates that iteration early; I don't think it
will skip to the next iteration.

Basically, what .parallel does under the hood is to create N jobs (where
N is the number of items to iterate over), representing N instances of
the loop body, and assign them to M worker threads to execute. Then it
waits until all N jobs have been completed before it returns.  Which
order the worker threads will pick up the loop body instances is not
specified, and generally is not predictable from user code.

The loop body in this case is translated into a delegate that gets
passed to the task pool's .opApply method; each worker thread that picks
up a job simply invokes the delegate with the right value of the loop
variable. A `continue` translates to returning a specific magic value
from the delegate that tells .opApply that the loop body finished early.
AFAIK, the task pool does not act on this return value, i.e., the other
instances of the loop body will execute regardless.


T

-- 
Time flies like an arrow. Fruit flies like a banana.


Re: Creating immutable arrays in @safe code

2021-07-16 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jul 16, 2021 at 10:23:31PM +, Dennis via Digitalmars-d-learn wrote:
> On Friday, 16 July 2021 at 20:45:11 UTC, H. S. Teoh wrote:
> > Have you tried `pure`?
> 
> The code in question is all `@safe pure nothrow`.

Hmm, OK. Not sure why .array isn't being inferred as unique... but yeah,
you probably have to resort to using @trusted with .assumeUnique.


T

-- 
Тише едешь, дальше будешь.


Re: Creating immutable arrays in @safe code

2021-07-16 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jul 16, 2021 at 08:19:32PM +, Dennis via Digitalmars-d-learn wrote:
[...]
> ```D
> immutable(int)[] positive(int[] input) @safe
> {
> return input.filter!(x => x > 0).array;
> }
> ```
[...]
> I could make another primitive (`iarraySort`), but I wonder if there
> are more convenient ways to create immutable data in general?

Have you tried `pure`?


T

-- 
They say that "guns don't kill people, people kill people." Well I think the 
gun helps. If you just stood there and yelled BANG, I don't think you'd kill 
too many people. -- Eddie Izzard, Dressed to Kill


Re: Module import failing after $ dub add mypackage

2021-07-16 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jul 16, 2021 at 04:54:18PM +, Scotpip via Digitalmars-d-learn wrote:
[...]
> I simply need a fast binary serialisation lib to read and write a
> large list of structs to local disk - it's not for inter-app
> communication. The struct is simple and only contains primitive D data
> types. If you are aware of any package that would be a better bet I'd
> appreciate your advice. Or is there a more direct way to dump a list
> from memory to disk and read it back again?  This is the kind of
> low-level stuff that's rather new to me...

If your struct contains only POD types (no indirections), and you do not
need to share it across machines, then you could just write the raw
bytes to disk and read them back:

struct Data { ... }

// To write:
File myFile = ...;
// write number of items to disk somewhere
foreach (Data item; myList) {
myFile.rawWrite(()[0 .. 1]);
}

// To read:
File myFile = ...;
int numItems = /* read number of items from disk somewhere */;
foreach (i; 0 .. numItems) {
Data item;
myFile.rawRead(()[0 .. 1]);
appendToList(item);
}

If your data is in an array, it's even easier:

Data[] myData;
// write myData.length to disk somewhere
myFile.rawWrite(myData);

myData.length = /* read number of items from disk */;
myFile.rawRead(myData);

Note that the above only works if your data contains no indirections.
(Beware that strings *do* contain indirection unless you're using
fixed-length buffers.)  If there are indirections you'll need to do
something smarter.


T

-- 
The irony is that Bill Gates claims to be making a stable operating system and 
Linus Torvalds claims to be trying to take over the world. -- Anonymous


Re: Please help me understand this function signature: std.stdio.File.byLine

2021-07-15 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jul 15, 2021 at 08:24:57PM +, Scotpip via Digitalmars-d-learn wrote:
[...]
> For starters, it's now clear to me that a strong understanding of
> Templates is essential to make much headway - that's why I got stuck
> here. They are dealt with towards the back of the books, but you
> really can't understand much of the library code without them. That's
> the first gap I'm going to fill.
[...]

My personal favorite approach to D template functions is to not think of
them as templates in the first place, but rather as functions with
*compile-time* parameters (in addition to the usual runtime parameters).
I.e., parameters that get baked in at compile-time. Since the parameters
are processed at compile-time, they can do a more than the usual runtime
parameters can, such as receiving types and aliases and other such
things that only exist at compile-time.  The function can then act on
these arguments at compile-time to adapt itself to the task thus
specified, without incurring the runtime overhead of a runtime check.


T

-- 
There are two ways to write error-free programs; only the third one works.


Re: Please help me understand this function signature: std.stdio.File.byLine

2021-07-15 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jul 15, 2021 at 06:08:45PM +, Scotpip via Digitalmars-d-learn wrote:
[...]
> ```
> auto byLine(Terminator, Char) (
>   KeepTerminator keepTerminator = No.keepTerminator,
>   Terminator terminator = '\x0a'
> )
> if (isScalarType!Terminator);
> 
> auto byLine(Terminator, Char) (
>   KeepTerminator keepTerminator,
>   Terminator terminator
> )
> if (is(immutable(ElementEncodingType!Terminator) == immutable(Char)));
> ```
> 
> To specify the line ending, it appears to be asking for a type
> "Terminator" which I can't find in the library. Doing the obvious
> doesn't work:
> 
> ```
> // Err: cannot deduce function from argument types
> myFile.byLine(`\r\n`);
> ```
> Also, how would you specify the Char type as a parameter?

First, notice that there are two sets of parentheses in the above quoted
declarations. The first set are compile-time parameters (template
parameters), while the second are runtime parameters.

`Terminator` and `Char` are listed as compile-time parameters, meaning
that they are types specified by the caller, so there is no definition
for them -- the caller defines what they will be. (More on this later.)

Secondly, note the order of parameters in the second set of parentheses:
`keepTerminator` first, then `terminator`. This is why your example
above doesn't compile: you're trying to specify a terminator where the
function expects a KeepTerminator parameter.

Now, a fully-specified invocation of byLine would specify both
compile-time and runtime parameters, e.g.:

auto r = File(...)
.byLine!(string,char)(Yes.KeepTerminator, "\r\n");

In this case, Terminator == string, Char == char.

But generally, the D compiler is pretty good at inferring types for you
automatically, so in this case, since the runtime parameters already
adequately imply what the compile-time arguments will be, so you could
just leave them out and write simply:

auto r = File(...)
.byLine(Yes.KeepTerminator, "\r\n");


> The examples are unenlightening as they only show the default case, so
> any help would be much appreciated. Any wider tips on how to read
> these cryptic signatures would be a bonus!

Please file a bug against the documentation about this.  Examples should
cover not only the default case, but should also illustrate how to use
non-default values.  This is a shortcoming in the documentation.


T

-- 
MS Windows: 64-bit rehash of 32-bit extensions and a graphical shell for a 
16-bit patch to an 8-bit operating system originally coded for a 4-bit 
microprocessor, written by a 2-bit company that can't stand 1-bit of 
competition.


Re: How to create friends of a class at compile time?

2021-07-15 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jul 15, 2021 at 05:21:45PM +, Tejas via Digitalmars-d-learn wrote:
> I can do it like this in C++:
> ```
> template
> class def
> {
> friend typename abc;
> }
> ```
> 
> I am just hopelessly confused on how to achieve the same in D.

D does not have `friend` declarations. Equivalent functionality is
achieved by `private` being module-private rather than
aggregate-private, meaning that all you have to do is to put `abc` in
the same module as `def`, and it will have access to all `def`s private
members.

If, however, you're trying to inject friend access to something outside
def's module, then you might want to reconsider what you're trying to
accomplish and whether it can be done differently.


T

-- 
Obviously, some things aren't very obvious.


Re: Trivial simple OpenGl working example

2021-07-09 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jul 09, 2021 at 05:11:06AM +, Виталий Фадеев via 
Digitalmars-d-learn wrote:
[...]
> I using CPU Pentium B970 It is old CPU, but even it contains a
> graphics accelerator.
> Mesa DRI Intel(R) HD Graphics 2000 (SNB GT1), has 4 conveers on GPU.
> Smartphones also contains GPU.
> Because OpenGL has high priority.
[...]
> What about text rendering ?

Generally, text rendering on OpenGL is a huge pain to implement. This is
not specific to D, but to OpenGL in general, because OpenGL itself does
not have direct support for text rendering at all.  The usual route is
to use an existing text-rendering library like FreeType to rasterize
your text, then upload it as a texture to the GPU and render it as a
quad.

If you want to do a more modern approach, you could use signed distance
fields, but that requires some deep knowledge of how shaders work unless
you can find an off-the-shelf library that does it for you. You may
still end up needing FreeType or equivalent anyway, to get the SDFs in
the first place.

Here's something to start you off, if you don't already have an approach
in mind:

https://learnopengl.com/In-Practice/Text-Rendering


T

-- 
Chance favours the prepared mind. -- Louis Pasteur


Re: Error: function `...` without `this` cannot be `const`

2021-06-30 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jun 30, 2021 at 07:40:40PM +, someone via Digitalmars-d-learn wrote:
[...]
> @property int data() { return m_data; } // read property
[...]
> string something() @property { return this.whatever; }
[...]
> Now I am not sure which is the correct way.
[...]

Both are correct. :-)  It's up to personal style preference.


T

-- 
2+2=4. 2*2=4. 2^2=4. Therefore, +, *, and ^ are the same operation.


Re: Error: function `...` without `this` cannot be `const`

2021-06-30 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jun 30, 2021 at 05:47:05PM +, someone via Digitalmars-d-learn wrote:
[...]
> ```d
> public string getAmountSI(
>in float lnumAmount
>) const {
[...]
> }
> ```
> 
> I used to put all attributes BEFORE the function name which now I
> understand is completely wrong since they should follow the parameter
> declaration section because putting them before affects the function
> in other ways.

The `const` here is being applied to the implicit `this` parameter to
your function.  If your function is not a member function (does not have
an implicit `this` parameter), then the attribute is meaningless.


T

-- 
Give me some fresh salted fish, please.


Re: String front, back return code point/unit

2021-06-23 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jun 23, 2021 at 04:01:24PM +, vit via Digitalmars-d-learn wrote:
[...]
> My question is not about ranges/iterators but if is good idea
> autodecoding custom string or not.

No.  Autodecoding is one of the decisions we regret because it
introduces an unavoidable overhead on basically every string operation
in Phobos.

Autodecoding was introduced under the misunderstanding that code point
== grapheme, but unfortunately that is false.  So it fails to accomplish
its original purpose and on top of that introduces a performance
problem.  To accomplish its original purpose would require grapheme
decoding; but unfortunately that introduces an even worse performance
overhead (Unicode grapheme decoding is non-trivial).

tl;dr: don't do it.


T

-- 
Why are you blatanly misspelling "blatant"? -- Branden Robinson


Re: semi-final switch?

2021-06-17 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jun 17, 2021 at 05:41:28PM -0400, Steven Schveighoffer via 
Digitalmars-d-learn wrote:
[.[..]
> Oh, and to throw a monkey wrench in here, the value is a string, not
> an integer. So I can't use std.conv.to to verify the enum is valid
> (plus, then I'm running a switch twice).
> 
> Any ideas on better ways to handle this?
[...]

Why not just:

try {
MyEnum value = input.to!MyEnum;
} catch (Exception e) {
stderr.writeln("Invalid input");
}

?


T

-- 
People demand freedom of speech to make up for the freedom of thought which 
they avoid. -- Soren Aabye Kierkegaard (1813-1855)


Re: Arrays of variants, C++ vs D

2021-06-17 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jun 17, 2021 at 07:44:31PM +, JN via Digitalmars-d-learn wrote:
[...]
> Foo[int] foos = [
> 0: Foo("abc"),
> 1: Foo(5)
> ];
> }
> ```
> 
> Why does D need the explicit declarations whereas C++ can infer it?

Because D does not support implicit construction. The array literal is
parsed as-is, meaning string[int] is inferred rather than Foo[int]. So
the initialization fails because of a type mismatch.

Implicit construction has been asked for many times, but Walter has been
adamant about not allowing implicit construction in D.


T

-- 
Music critic: "That's an imitation fugue!"


Re: Can not get struct member addresses at compile time

2021-06-16 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jun 16, 2021 at 02:42:41PM -0700, Ali Çehreli via Digitalmars-d-learn 
wrote:
[...]
> Actually, it is news to me that the compiler can know (determine?) the
> address of a global variable.
[...]

The compiler does not (and cannot) know.  But the runtime dynamic linker
can, and does.  The two are bridged by the compiler emitting a
relocatable symbol for the address of the global variable, with a table
of relocations (offsets in the code) that the runtime linker patches the
actual addresses into when the program is executed.


T

-- 
War doesn't prove who's right, just who's left. -- BSD Games' Fortune


Re: Struct assignment fails, why?

2021-06-16 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jun 16, 2021 at 08:44:46PM +, Brian via Digitalmars-d-learn wrote:
[...]
> struct item
> {
> string name;
> int type;
> };
[...]
> new_item = { "item1", 1 };

The {...} initializer syntax is only available in variable declarations,
e.g.:

item i = { "item1", 1 };

You cannot use this syntax in assignment statements.

A simple alternative is to use constructor syntax for constructing an
instance of the struct:

new_item = item("item", 1);


T

-- 
Everybody talks about it, but nobody does anything about it!  -- Mark Twain


Re: In general, who should do more work: popFront or front?

2021-06-15 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jun 15, 2021 at 02:20:11PM +, Paul Backus via Digitalmars-d-learn 
wrote:
[...]
> It's a time-space tradeoff. As you say, caching requires additional
> space to store the cached element. On the other hand, *not* caching
> means that you spend unnecessary time computing the next element in
> cases where the range is only partially consumed. For example:
> 
> ```d
> import std.range: generate, take;
> import std.algorithm: each;
> import std.stdio: writeln;
> 
> generate!someExpensiveFunction.take(3).each!writeln;
> ```
> 
> Naively, you'd expect that `someExpensiveFunction` would be called 3
> times--but it is actually called 4 times, because `generate` does its
> work in its constructor and `popFront` instead of in `front`.

One way to address this is to make the computation lazy: the element is
only computed once on demand, and once computed it's cached.  But of
course, this is probably overkill on many ranges.

So the long answer is, it depends. :-)


T

-- 
It is not the employer who pays the wages. Employers only handle the money. It 
is the customer who pays the wages. -- Henry Ford


Re: Inclusion of Parenthesis on Certain Functions

2021-06-13 Thread H. S. Teoh via Digitalmars-d-learn
On Sun, Jun 13, 2021 at 03:45:53PM +, Justin Choi via Digitalmars-d-learn 
wrote:
> I'm currently learning D right now, and I was wondering why certain
> functions like std.stdio.readln can work both with and without
> parenthesis for the function call. I've tried looking through the
> documentation but can't find an explanation for why you can use it
> without parenthesis.

In D, parentheses for function calls are optional when there are no
arguments. So:

func();

can be shortened to:

func;

When UFCS is in effect, the empty parentheses on the right side of the
function call are also optional:

func(abc);

can be rewritten as:

abc.func;


T

-- 
People demand freedom of speech to make up for the freedom of thought which 
they avoid. -- Soren Aabye Kierkegaard (1813-1855)


Re: Unittests not firing?

2021-06-11 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jun 11, 2021 at 02:05:31PM -0700, H. S. Teoh wrote:
[...]
> Huh, that doesn't look right. This was fixed since June last year, so it
> *should* have made it into the latest compiler releases already. Unless
> this one was missed somehow (but I doubt it).
[...]

Just checked on LDC 1.26.0, the message has already been fixed.  I
seriously doubt the beta would have the fix reverted somehow; this seems
to be a sign that your druntime is indeed out-of-sync with your
compiler.  You should check your system for stray stale copies of
druntime.


T

-- 
Caffeine underflow. Brain dumped.


Re: Unittests not firing?

2021-06-11 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jun 11, 2021 at 08:30:28PM +, Mike Brown via Digitalmars-d-learn 
wrote:
> On Friday, 11 June 2021 at 16:28:48 UTC, H. S. Teoh wrote:
> > On Fri, Jun 11, 2021 at 03:20:49PM +, Mike Brown via
> > Digitalmars-d-learn wrote:
> > > On Friday, 11 June 2021 at 15:13:17 UTC, rikki cattermole wrote:
> > [...]
> > > Right OK, mine says 1/1 unittests failed - but this should say
> > > Modules?
> > > 
> > > I will interpret it as Modules, ty!
> > 
> > This is a bug that was fixed in more recent versions of druntime.
> > Basically it was a misleading message because the count is the
> > number of modules, not the number of individual tests.
[...]
> OK, thank you - Im using LDC 1.27.0-beta1 which looks to be the newest
> I can find, is there a way to update the druntime manually?

Huh, that doesn't look right. This was fixed since June last year, so it
*should* have made it into the latest compiler releases already. Unless
this one was missed somehow (but I doubt it).


> I've problems with exceptions that might be related to me being out of
> date?
[...]

Are you sure your druntime is up-to-date with your LDC version?  One
thing to beware of is stale copies of druntime lying around that the
compiler picked up instead of the latest version.  This may lead to
subtle discrepancies that cause strange runtime problems like runtime
crashes or other odd behaviours.  (Though generally this shouldn't be a
problem with LDC, it's more commonly a problem with DMD installations.)


T

-- 
If the comments and the code disagree, it's likely that *both* are wrong. -- 
Christopher


Re: Two interpretations

2021-06-11 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jun 11, 2021 at 03:00:00PM +, JG via Digitalmars-d-learn wrote:
> Is it specified somewhere which way the following program will be
> interpreted?
> 
> import std;
> 
> struct A
> {
> int x=17;
> }
> 
> int x(A a)
> {
> return 100*a.x;
> }
> 
> void main()
> {
> A a;
>writeln(a.x);
> }

The rule is that member functions will always take precedence over UFCS.
UFCS only kicks in when the member function of that name cannot be
found.


T

-- 
For every argument for something, there is always an equal and opposite 
argument against it. Debates don't give answers, only wounded or inflated egos.


Re: Unittests not firing?

2021-06-11 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Jun 11, 2021 at 03:20:49PM +, Mike Brown via Digitalmars-d-learn 
wrote:
> On Friday, 11 June 2021 at 15:13:17 UTC, rikki cattermole wrote:
[...]
> Right OK, mine says 1/1 unittests failed - but this should say
> Modules?
> 
> I will interpret it as Modules, ty!

This is a bug that was fixed in more recent versions of druntime.
Basically it was a misleading message because the count is the number of
modules, not the number of individual tests.


T

-- 
Дерево держится корнями, а человек - друзьями.


Re: Faster Dlang Execution

2021-06-08 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jun 08, 2021 at 05:10:47PM +, seany via Digitalmars-d-learn wrote:
[...]
> Profiling doesn't help, because different input is causing different
> parts of the program to become slow.
[...]

Do you have any more specific information about what kind of inputs
cause which parts of the program to slow down?  Without more details
it's hard to say what the problem is.

But I'd say, if you care about performance you should fix *all* of the
slow parts that your profiler finds.

There are some performance best practices that you should follow, such
as reduce frequent GC allocations, avoid expensive algorithms (like
O(n^2) or worse) where possible, avoid excessive copying of data,
perform I/O in larger blocks instead of small bits at a time, avoid
excessive indirection (final methods where they don't need to be
virtual, by-value types instead of deep dereferencing, etc.), cache
frequently-computed results, etc..

But more importantly, if you can elaborate a bit more on what your
program is trying to do, it would help us give more specific
recommendations. There may be domain-specific optimizations that you
could apply as well.


T

-- 
MS Windows: 64-bit rehash of 32-bit extensions and a graphical shell for a 
16-bit patch to an 8-bit operating system originally coded for a 4-bit 
microprocessor, written by a 2-bit company that can't stand 1-bit of 
competition.


Re: how to enable safeD ? dmd.conf ? dmd switch ?

2021-06-07 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Jun 08, 2021 at 02:47:18AM +, someone via Digitalmars-d-learn wrote:
> https://dlang.org/articles/safed.html
> https://dlang.org/dmd-linux.html#switches
> http://ddili.org/ders/d.en/functions_more.html
> 
> Neither man dmd nor man dmd.conf appear to have a related/switch
> setting.
> 
> Does it means safeD is achieved by placing @safe attributes all over
> the place ? Or is it achieved by setting some global switch elsewhere
> ? Am I missing something ?

Annotate your functions with @safe.


T

-- 
Those who don't understand D are condemned to reinvent it, poorly. -- Daniel N


Re: is it possible to have a default property for any given class ?

2021-06-07 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Jun 07, 2021 at 03:26:27PM +, someone via Digitalmars-d-learn wrote:
> Consider the following code:
> 
> ```d
> class classComputer {
[...]
> }
> 
> class classComputers {
> 
>classComputers lhs;
>classComputers rhs;
> 
>int opApply(int delegate(classComputers) dg) { /// boilerplate code to
> handle the class's default collection
> 
>   if (lhs && lhs.opApply(dg)) return 1;
>   if (dg(this)) return 1;
>   if (rhs && rhs.opApply(dg)) return 1;
>   return 0;
> 
>}
> 
>public classComputer[] computers; /// how can I tag this as the default
> property ?

alias computers this;

> 
> }
> 
> void main (
> 
>) {
> 
>classComputers lobjComputers = new classComputers;
>lobjComputers.computers ~= new classComputer("dell");
>lobjComputers.computers ~= new classComputer("ibm");
>lobjComputers.computers ~= new classComputer("apple");
>lobjComputers.computers[1].name = r"lenovo";
> 
>foreach(lobjComputer; lobjComputers.computers) {
> writeln(lobjComputer.name); }
> 
>///foreach(lobjComputer; lobjComputers) { writeln(lobjComputer.name); }
> /// with default property (if possible)
> 
> }
> ```
> 
> The above code works correctly, however, avoiding the redundancy of
> lobjComputers.computers will be a plus.
> 
> Also tell me if the collection is implemented the right way, it is my
> first code using the opApply() delegate which I don't deeply
> understand for the time being.

It's very simple. Whenever some non-array object appears on the right
side of a foreach() statement, the compiler looks for a method on the
object called .opApply. If it exists, the loop body is passed to that
method as a delegate.  IOW:

// This:
foreach (item; myCollection) {
/* loop body here */
}

// Gets translated to this:
myCollection.opApply((item) { /* loop body here */ });


Given that, your .opApply method doesn't really do what you want. It
should instead be written like this:

// N.B.: dg is NOT the type of the collection, but the
// individual item you want to iterate over.
int opApply(int delegate(classComputer) dg)
{
// Loop over the computers in the current node first
foreach (computer; computers) {
// Pass single item to loop body.
auto ret = dg(computer);

// N.B.: do NOT assume a non-zero return value
// will always be 1; it may not be if your loop
// body contains `break` or `continue`.
if (ret) return ret;
}

// Now recurse child nodes
if (lhs) {
auto ret = lhs.opApply(dg);
if (ret) return ret; // again, don't assume it will be 1
}
if (rhs) {
auto ret = rhs.opApply(dg);
if (ret) return ret; // again, don't assume it will be 1
}
return 0;
}


T

-- 
Which is worse: ignorance or apathy? Who knows? Who cares? -- Erich Schubert


Re: regarding what seems (to me) unnecessary casts on integer expressions

2021-06-07 Thread H. S. Teoh via Digitalmars-d-learn
On Sat, Jun 05, 2021 at 01:46:45AM +, someone via Digitalmars-d-learn wrote:
[...]
> As I am writing code today I am encountering a lot of these situations.
> 
> cast(ushort)(this.pintBottom1 - 1)
> 
> My first walkaround for this was intuitive:
> 
> this.pintBottom1 - cast(ushort) 1 /// I didn't know if eg: 1S was
> possible which should have been the proper way to handle it
> 
> ... since pintBottom was already defined as ushort, but it didn't work
> also, so I ended with cast(ushort)(this.pintBottom1 - 1). I don't
> understand how to write typed code in D then. What's the point of
> declaring, for instance ushort's if then nothing will treat them as
> ushort's and I have to manually cast() everything to ushort() all the
> time ?

Here's my solution to D's short integer cast-madness: abstract it away
in an infectious wrapper type.  Save the following code into a file
called nopromote.d, import it, and whenever you have an expression
involving shorts, bytes, etc., that you don't want to write a cast for,
just insert .np (for "no-promote") somewhere in the expression (see
unittests below for concrete examples).


/**
 * Truncating wrapper around built-in narrow ints to work around stupid
 * casts.
 */
module nopromote;

enum isNarrowInt(T) = is(T : int) || is(T : uint);

/**
 * A wrapper around a built-in narrow int that truncates the result of
 * arithmetic operations to the narrow type, overriding built-in int promotion
 * rules.
 */
struct Np(T)
if (isNarrowInt!T)
{
T impl;
alias impl this;

/**
 * Truncating binary operator.
 */
Np opBinary(string op, U)(U u)
if (is(typeof((T x, U y) => mixin("x " ~ op ~ " y"
{
return Np(cast(T) mixin("this.impl " ~ op ~ " u"));
}

/**
 * Truncating unary operator.
 */
Np opUnary(string op)()
if (is(typeof((T x) => mixin(op ~ "cast(int) x"
{
return Np(cast(T) mixin(op ~ " cast(int) this.impl"));
}

/**
 * Infectiousness: any expression containing Np should automatically use Np
 * operator semantics.
 */
Np opBinaryRight(string op, U)(U u)
if (is(typeof((T x, U y) => mixin("x " ~ op ~ " y"
{
return Np(cast(T) mixin("u " ~ op ~ " this.impl"));
}
}

/**
 * Returns: A lightweight wrapped type that overrides built-in arithmetic
 * operators to always truncate to the given type without promoting to int or
 * uint.
 */
auto np(T)(T t)
if (isNarrowInt!T)
{
return Np!T(t);
}

// Test binary ops
@safe unittest
{
ubyte x = 1;
ubyte y = 2;
auto z = x.np + y;
static assert(is(typeof(z) : ubyte));
assert(z == 3);

byte zz = x.np + y;
assert(zz == 3);

x = 255;
z = x.np + y;
assert(z == 1);
}

@safe unittest
{
byte x = 123;
byte y = 5;
auto z = x.np + y;
static assert(is(typeof(z) : byte));
assert(z == byte.min);

byte zz = x.np + y;
assert(zz == byte.min);
}

@safe unittest
{
import std.random;
short x = cast(short) uniform(0, 10);
short y = 10;
auto z = x.np + y;
static assert(is(typeof(z) : short));
assert(z == x + 10);

short s = x.np + y;
assert(s == x + 10);
}

// Test unary ops
@safe unittest
{
byte b = 10;
auto c = -b.np;
static assert(is(typeof(c) : byte));
assert(c == -10);

ubyte ub = 16;
auto uc = -ub.np;
static assert(is(typeof(uc) : ubyte));
assert(uc == 0xF0);
}

version(unittest)
{
// These tests are put here as actual module functions, to force optimizer
// not to discard calls to these functions, so that we can see the actual
// generated code.
byte byteNegate(byte b) { return -b.np; }
ubyte ubyteNegate(ubyte b) { return -b.np; }

byte byteTest1(int choice, byte a, byte b)
{
if (choice == 1)
return a.np + b;
if (choice == 2)
return a.np / b;
assert(0);
}

short shortAdd(short a, short b) { return a.np + b; }

// Test opBinaryRight
byte byteRightTest(byte a, byte c)
{
auto result = a + c.np;
static assert(is(typeof(result) : byte));
return result;
}

unittest
{
assert(byteRightTest(127, 1) == byte.min);
}

short multiTest1(short x, short y)
{
return short(2) + 2*(x - y.np);
}

unittest
{
// Test wraparound semantics.
assert(multiTest1(32767, 16384) == short.min);
}

short multiTest2(short a, short b)
{
short x = a;
short y = b;
return (2*x + 1) * (y.np/2 - 1);
}

unittest
{
assert(multiTest2(1, 4) == 3);
}
}

// vim:set ai sw=4 ts=4 et:



T

-- 
The two rules of success: 1. Don't tell everything you know. -- YHL


Re: General rule when not to write ;

2021-05-19 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, May 19, 2021 at 05:53:12PM +, Alain De Vos via Digitalmars-d-learn 
wrote:
> It seems I need }; for a function a delegate and an alias.
> ```
> double function(int) F = function double(int x) {return x/10.0;};
> double delegate(int)   D = delegate double(int x) {return c*x/10.0;};
> alias myfunx=function int(int number) { return number; };
> ```

The ';' here is for terminating the alias, it is not part of the
delegate.

Basically, the grammar is this:

alias SYMBOL = DEFINITION ;

It just so happens that DEFINITION here is a function literal:

delegate ReturnType(...) { ... }

If you substitute this into the grammar, you get:

alias SYMBOL = delegate ReturnType(...) { ... } ;

That's all there is to it.  This isn't rocket science.


T

-- 
Don't drink and derive. Alcohol and algebra don't mix.


Re: stack out of scope ?

2021-05-16 Thread H. S. Teoh via Digitalmars-d-learn
On Sun, May 16, 2021 at 06:33:04PM +, Alain De Vos via Digitalmars-d-learn 
wrote:
> On Sunday, 16 May 2021 at 18:27:40 UTC, H. S. Teoh wrote:
[...]
> > -snip-
> > import std.stdio:writeln;
> > 
> > int [] fun() @safe {// N.B.: need @safe
> > int[3]s=[1,2,3];
> > int[] r=s;
> > return r;
> > }
> > 
> > void main() @safe { // N.B.: need @safe
> > writeln(fun()[0]);
> > }
> > -snip-
> > 
> > 
> > LDC output:
> > 
> > -snip-
> > $ ldc2 -dip1000 /tmp/test.d
> > /tmp/test.d(6): Error: scope variable `r` may not be returned
> > -snip-
[...]
> So I put everywhere @safe ?

Or put `@safe:` at the top of the file.


> When not ?

Sometimes when you need to perform a system operation that you know is
safe, but the compiler cannot prove is safe.  Or you need to call a
@system function (e.g. a C library).


T

-- 
Маленькие детки - маленькие бедки.


Re: stack out of scope ?

2021-05-16 Thread H. S. Teoh via Digitalmars-d-learn
On Sun, May 16, 2021 at 05:24:40PM +, Alain De Vos via Digitalmars-d-learn 
wrote:
> On Sunday, 16 May 2021 at 16:58:15 UTC, H. S. Teoh wrote:
> > On Sun, May 16, 2021 at 04:40:53PM +, Alain De Vos via
> > Digitalmars-d-learn wrote:
> > > This works also,
> > > 
> > > ```
> > > import std.stdio:writeln;
> > > 
> > > int [] fun(){
> > >   int[3]s=[1,2,3];
> > >   int[] r=s;
> > >   return r;
> > > }
> > > 
> > > void main(){
> > >   writeln(fun()[0]);
> > > }
> > > ```
> > 
> > https://issues.dlang.org/show_bug.cgi?id=15932
> > 
> > Though I believe if you compile with -dip25 -dip1000 the compiler should
> > emit an error for the above code.  If not, please file a bug against
> > -dip1000.
[...]
> I use ldc2. No dip flags here.

-snip-
import std.stdio:writeln;

int [] fun() @safe {// N.B.: need @safe
int[3]s=[1,2,3];
int[] r=s;
return r;
}

void main() @safe { // N.B.: need @safe
writeln(fun()[0]);
}
-snip-


LDC output:

-snip-
$ ldc2 -dip1000 /tmp/test.d
/tmp/test.d(6): Error: scope variable `r` may not be returned
-snip-


T

-- 
People say I'm indecisive, but I'm not sure about that. -- YHL, CONLANG


Re: stack out of scope ?

2021-05-16 Thread H. S. Teoh via Digitalmars-d-learn
On Sun, May 16, 2021 at 04:40:53PM +, Alain De Vos via Digitalmars-d-learn 
wrote:
> This works also,
> 
> ```
> import std.stdio:writeln;
> 
> int [] fun(){
>   int[3]s=[1,2,3];
>   int[] r=s;
>   return r;
> } 
> 
> void main(){
>   writeln(fun()[0]);
> }
> ```

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

Though I believe if you compile with -dip25 -dip1000 the compiler should
emit an error for the above code.  If not, please file a bug against
-dip1000.


T

-- 
Obviously, some things aren't very obvious.


Re: ugly and/or useless features in the language.

2021-05-16 Thread H. S. Teoh via Digitalmars-d-learn
On Sat, May 15, 2021 at 02:31:08PM +, Alain De Vos via Digitalmars-d-learn 
wrote:
> Which parts in dlang don't you use and why ?
> 
> Personally i have no need for enum types, immutable is doing fine.
> Auto return types i find dangerous to use.
> Voldermont types.
> Named initialiser.
> Tuple features.
> Maybe some other ?
> Feature creep can make your own code unreadable.
> 
> Offcourse taste can very from person to person.

I cannot live without auto return types and Voldemort types. They are my
bread and butter. Take them away, and I might as well go back to C/C++.

Also, unittests. The quality of my code has improved by leaps and bounds
ever since I started writing unittests, and their convenience (you can
write them literally next to the code they test) cannot be overstated.

What I find inconvenient:
- const-correctness, including immutable. It's all nice and everything
  because of its strong guarantees, but that also greatly limits its
  usefulness.  In practice, I find that it's really only usable in
  self-contained, low-level code / leaf node modules in the program's
  dependency graph. For high-level code it quickly becomes a burden to
  maintain const-correctness, and often the need for casts will arise
  because there will always be *something* that wants logical const
  rather than physical const / immutable, so APIs that try to be const
  correct usually have bugs / missing cases where something should be
  const but can't be, or something should accept mutable but can't
  because of overzealous application of const.
- Don't get me started about inout, which is quirky, has ambiguous cases
  as soon as delegates / function pointers are involved, and just
  introduces weird corner cases into the type system. Terrible for
  generic code because of the difficulty of dealing with cases involving
  inout in a generic way.

What I find ugly:
- shared, and all of its quirks and incomplete implementation.
- The fact that byte + byte cannot be assigned back to a byte without a
  cast. The fact that f(1) will choose the f(bool) overload instead of
  the f(int) overload.  The fact that Walter insists that bool is a
  1-bit integral type instead of a true boolean type.
- Autodecoding in Phobos, the big wart that we still haven't rid
  ourselves of after so many years.
- Attribute proliferation.  We should have had type inference integrated
  into the language from the beginning, but alas, that ship has already
  long sailed and it's too late to change that now.
- Other incomplete / half-implemented stuff in D.


T

-- 
There are three kinds of people in the world: those who can count, and those 
who can't.


Re: Recommendations on avoiding range pipeline type hell

2021-05-16 Thread H. S. Teoh via Digitalmars-d-learn
On Sat, May 15, 2021 at 11:25:10AM +, Chris Piker via Digitalmars-d-learn 
wrote:
[...]
> Basically the issue is that if one attempts to make a range based
> pipeline aka:
> 
> ```d
> auto mega_range = range1.range2!(lambda2).range3!(lambda3);
> ```
> Then the type definition of mega_range is something in the order of:
> 
> ```d
>   TYPE_range3!( TYPE_range2!( TYPE_range1, TYPE_lamba2 ), TYPE_lambda3));
> ```
> So the type tree builds to infinity and the type of `range3` is very
> much determined by the lambda I gave to `range2`.  To me this seems
> kinda crazy.

Perhaps it's crazy, but as others have mentioned, these are Voldemort
types; you're not *meant* to know what the concrete type is, merely that
it satisfies the range API. It's sorta kinda like the compile-time
functional analogue of a Java-style interface: you're not meant to know
what the concrete derived type is, just that it implements that
interface.


[...]
> But, loops are bad.  On the D blog I've seen knowledgeable people say
> all loops are bugs.

I wouldn't say all loops are bugs. If they were, why does D still have
looping constructs? :D  But it's true that most loops should be
refactored into functional-style components instead. Nested loops are
especially evil if written carelessly or uncontrollably.


> But how do you get rid of them without descending into Type Hell(tm).

Generally, when using ranges you just let the compiler infer the type
for you, usually with `auto`:

auto mySuperLongPipeline = inputData
.map!(...)
.filter!(...)
.splitter!(...)
.joiner!(...)
.whateverElseYouGot();


> Is there anyway to get some type erasure on the stack?

You can wrap a range in a heap-allocated OO object using the helpers in
std.range.interfaces, e.g., .inputRangeObject.  Then you can use the
interface as a handle to refer to the range.

Once I wrote a program almost entirely in a single pipeline.  It started
from a math function, piped into an abstract 2D array (a generalization
of ranges), filtered, transformed, mapped into a color scheme,
superimposed on top of some rendered text, then piped to a
pipeline-based implementation of PNG-generation code that produced a
range of bytes in a PNG file that's then piped into
std.stdio.File.bufferedWrite.  The resulting type of the main pipeline
was so hilariously huge, that in an older version of dmd it produced a
mangled symbol several *megabytes* long (by that I mean the *name* of
the symbol was measured in MB), not to mention tickled several O(N^2)
algorithms in dmd that caused it to explode in memory consumption and
slow down to an unusable crawl.

The mangled symbol problem was shortly fixed, probably partly due to my
complaint about it :-P -- kudos to Rainer for the fix!

Eventually I inserted this line into my code:

.arrayObject// Behold, type erasure!

(which is my equivalent of .inputRangeObject) and immediately observed a
significant speedup in compilation time and reduction in executable
size. :-D

The pipeline-based PNG emitter also leaves a lot to be desired in terms
of runtime speed... if I were to do this again, I'd go for a traditional
imperative-style PNG generator with hand-coded loops instead of the
fancy pipeline-based one I wrote.

Pipelines are all good and everything, but sometimes you *really* just
need a good ole traditional OO-style heap allocation and hand-written
loop.  Don't pick a tool just because of the idealism behind it, I say,
pick the tool best suited for the job.


T

-- 
Computers aren't intelligent; they only think they are.


Re: CTFE Assignment to anonymous union shows unexpected behavior

2021-04-22 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 22, 2021 at 11:44:51PM +, Rekel via Digitalmars-d-learn wrote:
> On Thursday, 22 April 2021 at 23:41:33 UTC, H. S. Teoh wrote:
> > On Thu, Apr 22, 2021 at 10:47:17PM +, Rekel via Digitalmars-d-learn
> > wrote:
> > > I'm not sure why this is happening, but after simplifying my code
> > > I traced it back to what the title may suggest.
> > 
> > Keep in mind that CTFE does not support reinterpretation via unions,
> > i.e., reading values from a different field in a union than was
> > assigned. If you assign field A to a union, then you cannot read field B
> > from that union in CTFE. You can only do this at runtime, not in CTFE.
[...]
> I'm not sure what you mean,
> do you mean if i were to read the field during CTFE, or even if i read
> the field during runtime after initializing it using CTFE?

If you read the field during CTFE.  I've never tested initializing a
union in CTFE then reading it at runtime, though. Not sure exactly what
would happen in that case.


T

-- 
Recently, our IT department hired a bug-fix engineer. He used to work for 
Volkswagen.


Re: CTFE Assignment to anonymous union shows unexpected behavior

2021-04-22 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 22, 2021 at 10:47:17PM +, Rekel via Digitalmars-d-learn wrote:
> I'm not sure why this is happening, but after simplifying my code I
> traced it back to what the title may suggest.

Keep in mind that CTFE does not support reinterpretation via unions,
i.e., reading values from a different field in a union than was
assigned. If you assign field A to a union, then you cannot read field B
from that union in CTFE. You can only do this at runtime, not in CTFE.


T

-- 
There are two ways to write error-free programs; only the third one works.


Re: write once type?

2021-04-20 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Apr 20, 2021 at 03:56:33PM -0400, Steven Schveighoffer via 
Digitalmars-d-learn wrote:
[...]
> I'm wondering if anyone has a "Write once" type, that is, a type that
> allows you to write it exactly once, and is treated like
> initialization on first setting (i.e. allows writing to previously
> unused const data).

Maybe a const class?  The reference is null until you initialize it by
allocating a new object and initializing it in the ctor.

But sounds like you want a value type instead. Technically, allocating a
const class involves the GC assigning some region of memory to the
class, initializing it, then casting it to const. So I'd imagine that
the by-value equivalent would require a const cast somewhere, probably
in a @trusted block if you want it to work with @safe.

Which means that probably you'll need a @trusted cast somewhere in your
implementation.  So perhaps something like this:

struct WriteOnce(T) {
const T payload;
const bool isSet;

void opAssign(U : T)(U data)
in (!isSet)
{
assert(!isSet);
@trusted() {
*(cast()) = data;
*(cast()) = true;
}();
}
}


T

-- 
Prosperity breeds contempt, and poverty breeds consent. -- Suck.com


Re: How do I create classes dynamically?

2021-04-15 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 15, 2021 at 08:56:18PM +, mw via Digitalmars-d-learn wrote:
[...]
> of course, one can manually dispatch:
> 
> if  (userInputString == "cat") createCat();
> else if (userInputString == "dog") createDog();
> ...
> 
> but this this tedious.

---
// Disclaimer: this is proof of concept, I didn't actually run this yet
class Animal {}
class Cat : Animal {}
class Dog : Animal {}

alias SupportedTypes = AliasSeq!(Cat, Dog, /* whatever else you want here */);

string userInputString = ...;
Animal result;
SW: switch (userInputString) {
static foreach (T; SupportedTypes) {
case T.stringof:
result = new T;
break SW;
}
default:
throw new Exception("Unknown object type");
}
---


> I have a similar question: how to dynamically use user's input string
> as function name can call it? suppose the function has no argument.

Same idea:

---
// Disclaimer: this is proof of concept, I didn't actually run this yet
struct Dispatcher {
void bark() { ... }
void meow() { ... }
void moo() { ... }
... // whatever else you want here
}

Dispatcher disp;
string userInputString = ...;
SW: switch (userInputString) {
static foreach (fieldName; __traits(allMembers, disp)) {
static if (is(typeof(__traits(getMember, disp, fieldName))
== function)
{
case fieldName:
__traits(getMember, disp, fieldName)();
break SW;
}
}
}
---

Basically, the idea is to obtain a list of types/methods/whatever
somehow (either by explicitly listing instances, or via compile-time
introspection), then statically generate switch cases from it.  You can
eliminate many kinds of boilerplate using this little trick.


T

-- 
Береги платье снову, а здоровье смолоду. 


Re: Is there a more elegant way to do this in D?

2021-04-08 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 08, 2021 at 08:28:44PM +, Alain De Vos via Digitalmars-d-learn 
wrote:
> The ascii code of 0 is 48 so I think you can add everywhere 48 (but
> I'm not a specialist)

Why bother with remembering it's 48? Just add '0', like this:

int a = [1, 0, 1, 0, 1, ...];
string s = a.map!(i => cast(char)(i + '0')).array;
writeln(s);

Or better yet, if you just want to output it and don't need to store the
array, just use the range directly:

int a = [1, 0, 1, 0, 1, ...];
auto r = a.map!(i => cast(char)(i + '0'));
writeln(r);


T

-- 
People say I'm arrogant, and I'm proud of it.


Re: what exactly is string length?

2021-04-01 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Apr 02, 2021 at 05:05:21AM +, mw via Digitalmars-d-learn wrote:
[...]
> This is just an example, what if the exact length is not known
> statically, is there a functions to trim the `\0`s?

Another way, if you want to avoid the extra allocation, slice the static
array with .indexOf:

s[0 .. s.indexOf('\0')]

should give you the initial segment up to the first null.


T

-- 
Questions are the beginning of intelligence, but the fear of God is the 
beginning of wisdom.


Re: what exactly is string length?

2021-04-01 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Apr 02, 2021 at 05:05:21AM +, mw via Digitalmars-d-learn wrote:
[...]
> This is just an example, what if the exact length is not known
> statically, is there a functions to trim the `\0`s?

What about `s.until('\0')`?

Example:

auto s = "abc\0\0\0def";
auto t = "blah" ~ s.until('\0').array ~ "boo";


T

-- 
What do you call optometrist jokes? Vitreous humor.


Re: what exactly is string length?

2021-04-01 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Apr 02, 2021 at 04:32:53AM +, mw via Digitalmars-d-learn wrote:
[...]
> ---
> import std;
> import std.conv : text;
> 
> 
> void main()
> {
> char[6] s;
> s = "abc";
> writeln(s, s.length);  // abc6, ok it's the static array's length
> 
> string t = text("head-", s, "-tail");
> writeln(t, t.length);  // head-abc-tail16, why?
> }
> ---
> 
> Why the last output is 16 instead of 13, t's type is string here.

Because `s` contains 6 chars, and you only assigned 3 of them, so there
are 3 trailing null bytes that are inserted before "-tail". Null bytes
don't print anything, so you don't see them when printed as a string,
but if you cast it to ubyte[], you will see them:

writefln("%(%02X %)", t);
// Prints: 68 65 61 64 2D 61 62 63 00 00 00 2D 74 61 69 6C

Remember, this is D, not C. Strings are not terminated by nulls, so
appending the static array will append all 6 chars, including the nulls.


T

-- 
Holding a grudge is like drinking poison and hoping the other person dies. -- 
seen on the 'Net


Re: Need for speed

2021-04-01 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Apr 02, 2021 at 02:36:21AM +, Jon Degenhardt via 
Digitalmars-d-learn wrote:
> On Thursday, 1 April 2021 at 19:55:05 UTC, H. S. Teoh wrote:
[...]
> > It's interesting that whenever a question about D's performance pops
> > up in the forums, people tend to reach for optimization flags.  I
> > wouldn't say it doesn't help; but I've found that significant
> > performance improvements can usually be obtained by examining the
> > code first, and catching common newbie mistakes.  Those usually
> > account for the majority of the observed performance degradation.
> > 
> > Only after the code has been cleaned up and obvious mistakes fixed,
> > is it worth reaching for optimization flags, IMO.
> 
> This is my experience as well, and not just for D. Pick good
> algorithms and pay attention to memory allocation. Don't go crazy on
> the latter. Many people try to avoid GC at all costs, but I don't
> usually find it necessary to go quite that far. Very often simply
> reusing already allocated memory does the trick.

I've been saying this for years, the GC is (usually) not evil. It's
often quite easy to optimize away the main bottlenecks and any remaining
problem becomes not so important anymore.

For example, see this thread:


https://forum.dlang.org/post/mailman.1589.1415314819.9932.digitalmar...@puremagic.com

which is continued here (for some reason it was split -- the bad ole
Mailman bug, IIRC):


https://forum.dlang.org/post/mailman.1590.1415315739.9932.digitalmar...@puremagic.com


>From a starting point of about 20 seconds total running time, I reduced
it to about 6 seconds by the following fixes:

1) Reduce GC collection frequency: call GC.stop at start of program,
   then manually call GC.collect periodically.

2) Eliminate autodecoding (using .representation or .byChar).

3) Rewrite a hot inner loop using pointers instead of .countUntil.

4) Refactor the code to eliminate a redundant computation from an inner
   loop.

5) Judicious use of .assumeSafeAppend to prevent excessive array
   reallocations.

6) (Not described in the thread, but applied later) Reduce GC load even
   further by reusing an array that was being allocated per iteration in
   an inner loop before.

Of the above, (1), (2), (3), and (5) require only very small code
changes. (4) and (6) were a little more tricky, but were pretty
localised changes that did not take a long time to implement or affect a
lot of code.  They were all implemented in a short span of 2-3 days.

Compare this with outright writing @nogc code, which would require a LOT
more time & effort.


> The blog post I wrote a few years ago focuses on these ideas:
> https://dlang.org/blog/2017/05/24/faster-command-line-tools-in-d/

Very nice, and matches my experience with optimizing D code.


T

-- 
Век живи - век учись. А дураком помрёшь.


Re: Need for speed

2021-04-01 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 01, 2021 at 09:16:09PM +, Imperatorn via Digitalmars-d-learn 
wrote:
> On Thursday, 1 April 2021 at 21:13:18 UTC, H. S. Teoh wrote:
[...]
> > Thanks for the very interesting information; so it looks like most
> > of the time spent is actually in copying array elements than
> > anything else!
[...]
> Sorting takes longer proportionally though

I meant that most the time incurred by appending to the array element by
element is spent copying elements.

Obviously, sorting will not be as fast as copying array elements.


T

-- 
What do you mean the Internet isn't filled with subliminal messages? What about 
all those buttons marked "submit"??


Re: Need for speed

2021-04-01 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 01, 2021 at 01:17:15PM -0700, Ali Çehreli via Digitalmars-d-learn 
wrote:
> On 4/1/21 12:55 PM, H. S. Teoh wrote:
> 
> > - Constructing large arrays by appending 1 element at a time with
> > `~`.  Obviously, this requires many array reallocations and the
> > associated copying
> 
> And that may not be a contributing factor. :) The following program
> sees just 15 allocations and 1722 element copies for 1 million
> appending operations:
[...]
> This is because the GC does not allocate if there are unused pages
> right after the array.

Right, but in a typical program it's unpredictable whether there will be
unused pages after the array.


> (However, increasing the element count to 10 million increases
> allocations slightly to 18 but element copies jump to 8 million.)
[...]

Thanks for the very interesting information; so it looks like most of
the time spent is actually in copying array elements than anything else!


T

-- 
Let's eat some disquits while we format the biskettes.


Re: Need for speed

2021-04-01 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 01, 2021 at 07:25:53PM +, matheus via Digitalmars-d-learn wrote:
[...]
> Since this is a "Learn" part of the Foruam, be careful with
> "-boundscheck=off".
> 
> I mean for this little snippet is OK, but for a other projects this my
> be wrong, and as it says here:
> https://dlang.org/dmd-windows.html#switch-boundscheck
> 
> "This option should be used with caution and as a last resort to
> improve performance. Confirm turning off @safe bounds checks is
> worthwhile by benchmarking."
[...]

It's interesting that whenever a question about D's performance pops up
in the forums, people tend to reach for optimization flags.  I wouldn't
say it doesn't help; but I've found that significant performance
improvements can usually be obtained by examining the code first, and
catching common newbie mistakes.  Those usually account for the majority
of the observed performance degradation.

Only after the code has been cleaned up and obvious mistakes fixed, is
it worth reaching for optimization flags, IMO.

Common mistakes I've noticed include:

- Constructing large arrays by appending 1 element at a time with `~`.
  Obviously, this requires many array reallocations and the associated
  copying; not to mention greatly-increased GC load that could have been
  easily avoided by preallocation or using std.array.appender.

- Failing to move repeated computations (esp. inefficient ones) outside
  the inner loop.  Sometimes a good optimizing compiler is able to hoist
  it out automatically, but not always.

- Constructing lots of temporaries in inner loops as heap-allocated
  classes instead of by-value structs: the former leads to heavy GC
  load, not to mention memory allocation is generally slow and should be
  avoided inside inner loops. Heap-allocated objects also require
  indirections, which slow things down even more. The latter can be
  passed around in registers: no GC pressure, no indirections; so can
  significantly improve performance.

- Using O(N^2) (or other super-linear) algorithms with large data sets
  where a more efficient algorithm is available. This one ought to speak
  for itself. :-D  Nevertheless it still crops up from time to time, so
  deserves to be mentioned again.


T

-- 
Those who don't understand Unix are condemned to reinvent it, poorly.


Re: Need for speed

2021-04-01 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 01, 2021 at 04:52:17PM +, Nestor via Digitalmars-d-learn wrote:
[...]
> ```
> import std.stdio;
> import std.random;
> import std.datetime.stopwatch : benchmark, StopWatch, AutoStart;
> import std.algorithm;
> 
> void main()
> {
> auto sw = StopWatch(AutoStart.no);
> sw.start();
> int[] mylist;

Since the length of the array is already known beforehand, you could get
significant speedups by preallocating the array:

int[] mylist = new int[10];
for (int number ...)
{
...
mylist[number] = n;
}


> for (int number = 0; number < 10; ++number)
> {
> auto rnd = Random(unpredictableSeed);
[...]

Don't reseed the RNG every loop iteration. (1) It's very inefficient and
slow, and (2) it actually makes it *less* random than if you seeded it
only once at the start of the program.  Move this outside the loop, and
you should see some gains.


> auto n = uniform(0, 100, rnd);
> mylist ~= n;
> }
> mylist.sort();
> sw.stop();
> long msecs = sw.peek.total!"msecs";
> writefln("%s", msecs);
> }
[...]
> ```

Also, whenever performance matters, use gdc or ldc2 instead of dmd. Try
`ldc2 -O2`, for example.


I did a quick test with LDC, with a side-by-side comparison of your
original version and my improved version:

-
import std.stdio;
import std.random;
import std.datetime.stopwatch : benchmark, StopWatch, AutoStart;
import std.algorithm;

void original()
{
auto sw = StopWatch(AutoStart.no);
sw.start();
int[] mylist;
for (int number = 0; number < 10; ++number)
{
auto rnd = Random(unpredictableSeed);
auto n = uniform(0, 100, rnd);
mylist ~= n;
}
mylist.sort();
sw.stop();
long msecs = sw.peek.total!"msecs";
writefln("%s", msecs);
}

void improved()
{
auto sw = StopWatch(AutoStart.no);
sw.start();
int[] mylist = new int[10];
auto rnd = Random(unpredictableSeed);
for (int number = 0; number < 10; ++number)
{
auto n = uniform(0, 100, rnd);
mylist[number] = n;
}
mylist.sort();
sw.stop();
long msecs = sw.peek.total!"msecs";
writefln("%s", msecs);
}

void main()
{
original();
improved();
}
-


Here's the typical output:
-
209
5
-

As you can see, that's a 40x improvement in speed. ;-)

Assuming that the ~209 msec on my PC corresponds with your observed
280ms, and assuming that the 40x improvement will also apply on your
machine, the improved version should run in about 9-10 msec.  So this
*should* have give you a 4x speedup over the Python version, in theory.
I'd love to see how it actually measures on your machine, if you don't
mind. ;-)


T

-- 
Holding a grudge is like drinking poison and hoping the other person dies. -- 
seen on the 'Net


Re: Why I need DUB? Will never DMD don't just use import for import packages?

2021-03-29 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Mar 29, 2021 at 07:28:23PM +, Adam D. Ruppe via Digitalmars-d-learn 
wrote:
> On Monday, 29 March 2021 at 19:06:33 UTC, Marcone wrote:
> > Why can't I just use: import vibe.vibe; for import packages like Nim
> > or Python? Why I still use DUB?
> 
> I don't use dub. Just dmd -i after you set up the files in the right
> place.
> 
> Not all libraries support that but I only use my own libraries so it
> is fine.

I highly recommend Adam's arsd library (or collection of libraries).
Mostly just single files, with a few that have one or two dependencies,
you just copy the file(s) into your workspace and import them. That's
all.  No need for external tools to manage dependencies, no dependency
hell, just drop the file into your project and go.

arsd does have a dub thingy for those who want it, but I mostly just git
submodule it in my own projects or plain ole copy a couple o' files into
my workspace. No fuss, no muss, no hairy NP-complete dependency graphs,
the way it should be.


T

-- 
Having a smoking section in a restaurant is like having a peeing section in a 
swimming pool. -- Edward Burr 


Re: What is best way to read and interpret binary files?

2021-03-29 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Mar 30, 2021 at 12:32:36AM +, mw via Digitalmars-d-learn wrote:
> On Monday, 19 November 2018 at 22:32:55 UTC, H. S. Teoh wrote:
> > Actually, the case is unnecessary, because arrays implicitly convert
> > to void[], and pointers are sliceable.  So all you need is:
> > 
> > SomeStruct myStruct;
> > fd.rawRead(()[0 .. 1]);
> > 
> > This works for all POD types.
> > 
> > Writing the struct out to file is the same thing:
> > 
> > SomeStruct myStruct;
> > fd.rawWrite(()[0 .. 1]);
> 
> 
> This works, but I'm just wondering why we do not just add more
> functions to the library:
> 
>  rawRead(ref T t), and
>  rawWrite(ref T t)
> 
> to read & write single value.

If you wish, submit a PR for this.

It's not hard to write your own overloads for it, though:

void rawWrite(File f, ref T t) @trusted
{
f.rawWrite((cast(ubyte*) )[0 .. T.sizeof]);
}

// ditto for rawRead


T

-- 
A linguistics professor was lecturing to his class one day.
"In English," he said, "A double negative forms a positive. In some
languages, though, such as Russian, a double negative is still a
negative. However, there is no language wherein a double positive can
form a negative."
A voice from the back of the room piped up, "Yeah, yeah."


Re: How to delete dynamic array ?

2021-03-16 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Mar 16, 2021 at 11:28:00PM +, mw via Digitalmars-d-learn wrote:
[...]
> suppose:
> 
>   double[] data;  // D type: dynamic array
> 
> As of 2021 what's the correct way to allocate and deallocate (free
> memory to the system immediately) D's dynamic array?
[...]

Note that T[] is just a slice, not the dynamic array itself. The dynamic
array is allocated and managed by the GC when you append stuff to it, or
when you create a new array with `new` or an array literal.

None of the latter, however, precludes you from using T[] for memory
that you manage yourself. For example, you could do this:

double[] data;
data = cast(double[]) malloc(n * double.sizeof)[0 .. n];

Now you have a slice to memory you allocated yourself, and you have to
manage its lifetime manually.  When you're done with it:

free(data.ptr);
data = []; // null out dangling pointer, just in case

The GC does not get involved unless you actually allocate from it. As
long as .ptr does not point to GC-managed memory, the GC will not care
about it. (Be aware, though, that the ~ and ~= operators may allocate
from the GC, so you will have to refrain from using them. @nogc may help
in this regard.)


T

-- 
Computers shouldn't beep through the keyhole.


Re: Static initialization of associative arrays

2021-03-11 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Mar 11, 2021 at 06:06:35PM +, Chris Piker via Digitalmars-d-learn 
wrote:
[...]
> Today I ran across a situation where an immutable associative array
> would be handy. While perusing the language spec I noticed here:
> 
>   https://dlang.org/spec/hash-map.html#static_initialization
> 
> that this feature is not yet implemented.
[...]

The subsequent section on the linked page gives the solution /
workaround. Just declare your immutable AA without initialization, and
initialize it in a static ctor:

immutable int[string] aa;
shared static this() {
aa = [ "abc": 123, "def": 456, /* ... */ ];
}


T

-- 
INTEL = Only half of "intelligence".


Re: Broken examples

2021-03-05 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Mar 05, 2021 at 10:01:37PM +, Imperatorn via Digitalmars-d-learn 
wrote:
> Basically none of the examples on here compile:
> https://dlang.org/library/std/conv/parse.html
> 
> Any idea why?

File a bug.


T

-- 
By understanding a machine-oriented language, the programmer will tend to use a 
much more efficient method; it is much closer to reality. -- D. Knuth


Re: Can't I allocate at descontructor?

2021-03-05 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Mar 05, 2021 at 08:24:26PM +, Jack via Digitalmars-d-learn wrote:
> On Friday, 5 March 2021 at 20:18:44 UTC, Max Haughton wrote:
> > On Friday, 5 March 2021 at 20:13:54 UTC, Jack wrote:
[...]
> > > But the ones heap may never run at all, is that right?
> > 
> > You can't rely on the garbage collector for deterministic
> > destruction, no.
> 
> Are there some kind of replacement or I have to make my own
> finalize-like method, once I determine somewhat the application no
> longer need those resources?
[...]

If you know when you can deallocate something, that means you don't need
the GC to collect it, so you could just allocate it on the malloc heap
instead, and call destroy/free once you're done.  You could use the C
version of malloc/free.  You can also optionally use GC.malloc/GC.free.

E.g.:

class C {...}

import core.memory : GC;
C c = cast(C) GC.malloc(C.sizeof);
... // use c

// We're done with c, destroy it
destroy(c); // this will call the dtor
GC.free(cast(void*) c);
c = null; // optional, just to ensure we don't accidentally use it again


T

-- 
Freedom of speech: the whole world has no right *not* to hear my spouting off!


Re: Can't I allocate at descontructor?

2021-03-05 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Mar 05, 2021 at 08:03:58PM +, Jack via Digitalmars-d-learn wrote:
> On Friday, 5 March 2021 at 09:23:29 UTC, Mike Parker wrote:
> > On Friday, 5 March 2021 at 05:31:38 UTC, Jack wrote:
> > > The following code returns a memory error. I did notice it did
> > > happens whenever I did a memory allocation. Is this not possible
> > > in the descontrutor? if so, why?
> > 
> > https://dlang.org/blog/2021/03/04/symphony-of-destruction-structs-classes-and-the-gc-part-one/
> 
> thanks for such good article. So if the object was allocated on heap,
> there's no guarantee that the object's destrutor will be called at all?

Yes.

And also if it does get called, there's no guarantee what order it will
be called in w.r.t. other dtors. And you cannot perform any GC
operations in it.


> do destrutor allocate at stack are guarantee to be run?

Yes.


T

-- 
If it tastes good, it's probably bad for you.


Re: Is there any generic iteration function that stops at first match?

2021-03-04 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Mar 05, 2021 at 02:13:39AM +, Jack via Digitalmars-d-learn wrote:
> something like filter[1] but that stops at first match? are there any
> native functions for this in D or I have to write one? just making
> sure to not reinvent the wheel
[...]

Why not just .front?  E.g.:

int[] data = [ 1,2,3,4,5 ];
auto r = data.filter!(v => v % 2 == 0);
assert(r.front == 2);


T

-- 
There is no gravity. The earth sucks.


Re: How do I run multiple unittests with rdmd?

2021-03-04 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Mar 05, 2021 at 01:47:41AM +, Anthony via Digitalmars-d-learn wrote:
> Hello,
> 
> I'm trying to run multiple unittest files with rdmd.
> So far I use `find` to just pipe in the files. Eg:
> 
> 
> time find source -name *__tests.d -exec rdmd -unittest --main
> -I../libprelude/source -I../libparser/source -I../libgeometry/source
> -Isource {} \;
> 
> Is there an easier way to do this?

Do you have multiple applications, or a single application spread across
multiple sources?

In the latter case, you could just use `rdmd -unittest -i -run main.d`
(replace `main.d` with whatever source file contains main()) to
automatically compile all modules including their unittests *and* run
'em all in one shot.

Only in the former case would you need to use your `find` pipeline
above. :-)


T

-- 
Computers aren't intelligent; they only think they are.


Re: D's Continous Changing

2021-03-03 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Mar 04, 2021 at 06:43:57AM +, user1234 via Digitalmars-d-learn 
wrote:
> On Thursday, 4 March 2021 at 05:44:53 UTC, harakim wrote:
> > For the record, I was able to resolve all of my issues in about 7
> > hours.  That included upgrading from DerelictSDL to bindbc and
> > converting to use dub instead of make.
[...]
> > I also should mention that this project was probably last touched in
> > 2017. I thought I pulled it out a year ago, but that was a different
> > project.
> 
> otherwise another solution is to check every two monthes the sanity of
> your projects. E.g a montly cronjob on a CI service and that uses
> latest DMD Docker image. If it fails you got an email... It certainly
> cooler to take 5 mins every two monthes than 7 hours 4 years.

Y'know what'd be cool: if people could add their D projects to some kind
of master CI (don't know if the existing dmd/druntime/phobos CI config
allows this) so that whenever a change in the language causes breakage,
the relevant PR will get flagged for review.  I wouldn't say block the
PR altogether -- we don't want some obscure no-longer-maintained project
to hold back everyone else -- but at least flag it as a breaking change
so that the owner can be contacted to see if something could be worked
out.

I know we already do this for some key projects, but a large-scale
CI test would be nice, if we had the resources for it.


T

-- 
A linguistics professor was lecturing to his class one day. "In English," he 
said, "A double negative forms a positive. In some languages, though, such as 
Russian, a double negative is still a negative. However, there is no language 
wherein a double positive can form a negative." A voice from the back of the 
room piped up, "Yeah, yeah."


Re: How can I tell if the give parameter can be run at compile time?

2021-03-01 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Mar 01, 2021 at 08:05:57PM +, Jack via Digitalmars-d-learn wrote:
> bool g(T)(T)
> {
>   return __traits(compiles, mixin("{ enum a = t; }"));
> }
> 
> 
> int a;
> enum s = "";
> // both return false but g(s) is expected to return true
> pragma(msg, g(s));
> pragma(msg, g(a));

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


T

-- 
They pretend to pay us, and we pretend to work. -- Russian saying


Re: How do I check if a type is assignable to null at compile time?

2021-02-26 Thread H. S. Teoh via Digitalmars-d-learn
On Sat, Feb 27, 2021 at 01:03:56AM +, Jack via Digitalmars-d-learn wrote:
> On Friday, 26 February 2021 at 23:37:18 UTC, Murilo wrote:
> > On Friday, 26 February 2021 at 05:25:14 UTC, Jack wrote:
> > > I started with:
> > > 
> > > enum isAssignableNull(T) = is(T : Object) || isPointer(T);
> > > 
> > > but how do I cover all cases?
> > 
> > You can check if it's null with this `variable is null` and you
> > can test it with assert as in `assert(variable is null);`
> 
> I mean a give type T not variablee

Why not just:

enum isAssignableNull(T) = is(typeof((T t){ t = null; }));

?


T

-- 
What are you when you run out of Monet? Baroque.


Re: Can Metaprogramming Help Here?

2021-02-26 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Feb 26, 2021 at 11:37:18AM -0800, H. S. Teoh via Digitalmars-d-learn 
wrote:
> On Wed, Feb 24, 2021 at 08:10:30PM +, Mike Brown via Digitalmars-d-learn 
> wrote:
> [...]
> > Thank you for the reply. Im struggling extending this to get the
> > nesting working.
[...]

Alright, here's an actual working example. Instead of using classes, I
decided to use templates instead, but the underlying concept is the
same:

-snip--
template branch(string _ident, _values...) {
enum ident = _ident;
alias values = _values;
}

// I used strings for easier concatenation to code, otherwise we have to use
// std.conv to convert it which is slow in CTFE.
static immutable string[] primes = [
"2", "3", "5", "7", "11", "13", "17", "19", "23", "29", "31", "37",
"41", // fill in more if you need to
];

string genPrimeId(size_t[] indices)
in (indices.length > 0)
{
string result = primes[indices[0]];
foreach (i; indices[1 .. $]) {
result ~= "*" ~ primes[i];
}
return result;
}

template primeIdsImpl(size_t[] indices, Args...)
if (indices.length > 0 && Args.length > 0)
{
static if (Args.length == 1) {
static if (is(typeof(Args[0]) == string)) {
enum primeIdsImpl = Args[0] ~ "=" ~ genPrimeId(indices) 
~ ",\n";
} else {
enum primeIdsImpl = Args[0].ident ~ "=" ~ 
genPrimeId(indices) ~ ",\n" ~
primeIdsImpl!(indices ~ [ indices[$-1] + 1 ],
Args[0].values);
}
} else {
enum primeIdsImpl = primeIdsImpl!(indices, Args[0]) ~
primeIdsImpl!(indices[0 .. $-1] ~ [ indices[$-1] + 1 ],
Args[1 .. $]);
}
}

template primeIds(string enumName, Args...) if (Args.length > 0) {
enum primeIds = "enum " ~ enumName ~ " {\n" ~
primeIdsImpl!([0], Args) ~
"}";
}

mixin(primeIds!("token_type",
"endOfFile",
"unknown",
"newline",
branch!("identifier",
"userDefined",
"var",
"uses",
"constructor",
"do_",
"end_",
),
branch!("operator",
"copyAssignment",
),
));

void main() {
import std;
writefln("%s", token_type.identifier);
writefln("%d", token_type.identifier);
}
-snip--


You can change the mixin line to `pragma(msg, ...)` instead to see the
generated code string.

I noticed that the definitions of the first nested identifiers are
different from your original post; I don't know if this is a
misunderstanding on my side or an oversight on your part?  After
identifier=7, the next prime should be 11, not 13, so userDefined should
start with 11*identifier rather than 13*identifier.


T

-- 
Shin: (n.) A device for finding furniture in the dark.


Re: Can Metaprogramming Help Here?

2021-02-26 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Feb 24, 2021 at 08:10:30PM +, Mike Brown via Digitalmars-d-learn 
wrote:
[...]
> Thank you for the reply. Im struggling extending this to get the
> nesting working.
> 
> I'm trying something like:
> 
> string entry(string i, string[] inherit = []) {
>   return i;
> }
> 
> alias token_type2 = PrimeEnum!(
>   entry("unknown"),
>   entry("newline"),
>   entry("identifier"),
>   entry("var", ["identifier"]),
>   entry("userDefined", ["identifier"])
> );
> 
> Its worth noting that multiple inherited bases are needed too.
> 
> But I can't get those functions contexts linking, can I pass a
> function pointer as lazy into the PrimeEnum!() template?
> 
> Would it be easier to just parse the text at once into a single
> templating function?
[...]

Ah, so sorry, I completely overlooked the nesting part.  PrimeEnum as I
defined it in my first reply does not handle this at all, so it will
need to be extended.

Since we're dealing with a tree structure here, I think the best way is
to express the tree structure explicitly in a compile-time data
structure. Thanks to CTFE, this works pretty much exactly the same as
normal runtime data structures; the only difference is that they will be
processed at compile-time.

Here's a rough sketch of how I'd do it:

class Entry {
string ident;
Entry[] subentries;
this(string _id, Entry[] _subs = []) {
ident = _id;
subentries = _subs;
}
}

Entry[] makeIdentTrees() {
return [
new Entry("endOfFile"),
new Entry("unknown"),
new Entry("newline"),
new Entry("identifier", [
new Entry("userDefined"),
new Entry("var"),
new Entry("uses"),
... // you get the idea
],
new Entry("operator", [
new Entry("copyAssignment"),
... // etc.
]));
]
}

You'd then write a recursive function that traverses this tree, using a
compile-time array of prime numbers, and compute the enum values that
way.  Format that into D code as a string, and use mixin to actually
create the enum.  The function can be written just like any runtime D
code, as long as it does not use any CTFE-incompatible language
features.

string genEnum(Entry[] entries) {
string code;
... // traverse tree and generate D code here
return code;
}

// Create the enum
mixin(genEnum(makeIdentTrees()));


T

-- 
A mathematician learns more and more about less and less, until he knows 
everything about nothing; whereas a philospher learns less and less about more 
and more, until he knows nothing about everything.


Re: DUB is not working correctly

2021-02-26 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Feb 26, 2021 at 06:53:32PM +, evilrat via Digitalmars-d-learn wrote:
> On Friday, 26 February 2021 at 18:20:38 UTC, Maxim wrote:
> > On Friday, 26 February 2021 at 17:57:12 UTC, ryuukk_ wrote:
> > > "targetType": "executable",
> > > 
> > > and it should just run using "dub run"
> > 
> > Unfortunately, the problem remains :/
> 
> Looks like something specific to your machine.
> 
> The last thing I could think of is to run dub with -v flag (verbose
> mode), look for all steps performed and check the output for anything
> that potentially could cause a failure.
[...]

And possibly paste the output of -v here, somebody may be able to
diagnose what went wrong then.


--T


Re: DUB is not working correctly

2021-02-24 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Feb 24, 2021 at 06:32:00PM +, Maxim via Digitalmars-d-learn wrote:
> On Wednesday, 24 February 2021 at 18:21:40 UTC, evilrat wrote:
> > On Wednesday, 24 February 2021 at 17:45:56 UTC, Maxim wrote:
> > > 
> > > Unfortunately, I tried bindbc-sfml package but the problem is
> > > still existing. I also started a new project and without any
> > > changes ran it but the result was the same. Anyway, thank you so
> > > much for your help!
> > 
> > does it works for an empty project created with 'dub init' from
> > terminal?
> 
> No, it doesn't work on an empty project with 'dub init'.

Sounds like something is wrong with your toolchain installation. An
empty project ought to work.  Maybe try a fresh reinstall?


T

-- 
BREAKFAST.COM halted...Cereal Port Not Responding. -- YHL


Re: Compile-Time Function Parameters That Aren't Types?

2021-02-23 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Feb 24, 2021 at 03:52:57AM +, Kyle Ingraham via Digitalmars-d-learn 
wrote:
[...]
> I was under the impression that compile-time or template parameters
> were only for types.

In D, template parameters can take not only types, but almost any type
(provided they are constructible at compile-time).  Basically, D views
template parameters as *compile-time parameters*; i.e., they are treated
like ordinary parameters, except that they happen to be passed at
compile-time.


> [...] Why would one write a function this way?

Usually it's when there's a decision that needs to be made at
compile-time (or desirable to be made at compile-time for whatever
reason).  For example, if there are two very different branches of code
that should run depending on the value of parameter, and user code is
expected to want only one or the other code path, so fixing the code
path at compile-time may be advantageous.

D's operator overloading is one example of this.  It takes a
compile-time string containing the operator, which lets the implementor
choose whether to implement multiple operator overloads separately, or
grouped together in a common implementation. E.g.:

struct MyObject {
private int impl;

/**
 * Example of separate implementations for operators:
 */
MyObject opBinary(string op)(MyObject b)
if (op == "*")
{
return ... /* multiplication algorithm here */;
}

/// ditto
MyObject opBinary(string op)(MyObject b)
if (op == "/")
{
return ... /* division algorithm here */;
}

/**
 * Example of multiple operators sharing a common
 * implementation.
 */
MyObject opBinary(string op)(MyObject b)
if (op == "+" || op == "-")
{
// Use mixin to implement both operators at
// once.  Avoids excessive boilerplate.
return MyObject(mixin("impl" ~ op ~ "b.impl"));
}
}

Passing the operator as a compile-time parameter gives the flexibility
to implement different operators separately, or together with a common
implementation, or some combination of both as in the above example.


T

-- 
Real men don't take backups. They put their source on a public FTP-server and 
let the world mirror it. -- Linus Torvalds


Re: Can Metaprogramming Help Here?

2021-02-23 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Feb 23, 2021 at 10:24:50PM +, Mike Brown via Digitalmars-d-learn 
wrote:
> Hi all,
> 
> Im porting some C++ code, which has a mess of a section that
> implements prime number type id's. I've had to smother it to death
> with test cases to get it reliable, I think metaprogramming that D
> provides is the better solution - Id rather not reimplement that C++
> mess ideally.

Try something like this:

-snip-
import std;

int[] firstNPrimes(int n) {
// FIXME: replace this with actual primes computation
return [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 ];
}

string genEnum(string enumName, idents...)() {
string code = "enum " ~ enumName ~ " {";
auto primes = firstNPrimes(idents.length);
foreach (i, ident; idents) {
code ~= ident ~ " = " ~ primes[i].to!string ~ ", ";
}
code ~= "}";
return code;
}

template PrimeEnum(idents...) {
mixin(genEnum!("PrimeEnum", idents));
}

alias MyEnum = PrimeEnum!(
"unknown", "newline", "identifier", "var", "user_defined",
);

void main() {
writefln("%(%d\n%)", [
MyEnum.unknown,
MyEnum.newline,
MyEnum.identifier,
MyEnum.var,
MyEnum.user_defined
]);
}
-snip-


You can substitute the body of firstNPrimes with any standard
prime-generation algorithm. As long as it's not too heavyweight, you
should be able to get it to compile without the compiler soaking up
unreasonable amounts of memory. :-D  If you find the compiler using up
too much memory, try precomputing the list of primes beforehand and
pasting it into firstNPrimes (so that the CTFE engine doesn't have to
recompute it every time you compile).

Note that PrimeEnum can be used to generate any number of enums you wish
to have prime values.  Or if you replace the call to firstNPrimes with
something else, you can generate enums whose identifiers map to any
integer sequence of your choosing.


T

-- 
Bare foot: (n.) A device for locating thumb tacks on the floor.


Re: How to get Laptop battery level

2021-02-22 Thread H. S. Teoh via Digitalmars-d-learn
On Mon, Feb 22, 2021 at 08:59:01PM +, Greatsam4sure via Digitalmars-d-learn 
wrote:
> Dlang is a system programming language. How do I access the battery
> level of my system using code in dlang? I will appreciate vide sample

There is no universal API for this.  It depends on which OS you're
using.  For that, you need to consult your OS's documentation. Most
likely there will be some kind of C API or system library that could
give you this information.

D can't possibly provide a universal API for something like this because
it varies too widely -- some platforms do not have any meaningful
notion of "battery level", whereas other systems may well have multiple
"battery levels" and it would be ambiguous which one is meant.  If you
want to do systems programming you have to know the system you're
programming, and be prepared to call OS APIs yourself.


T

-- 
The irony is that Bill Gates claims to be making a stable operating system and 
Linus Torvalds claims to be trying to take over the world. -- Anonymous


Re: Struct delegate access corruption

2021-02-17 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Feb 17, 2021 at 03:38:00PM +, z via Digitalmars-d-learn wrote:
> So i've upgraded one of my structs to use the more flexible delegates
> instead of function pointers but when the member function tries to
> access the struct's members, the contents are random and the program
> fails.

You're likely running into the struct self-reference problem.  Keep in
mind that in D, structs are what Andrei calls "glorified ints", i.e.,
they are value types that get freely copied around and passed around in
registers.  Meaning that the address of a struct is likely to change
(and change a lot as it gets passed around), unless you explicitly
allocated it on the heap.  So if you have any pointers to the struct
(including implicit pointers like delegate context pointers) stored
inside itself, they are highly likely to become dangling pointers as the
struct gets copied to another place and the old copy goes out of scope.

I.e., the following is NOT a good idea:

struct S {
void delegate() member;
this() {
member = 
}
private void impl();
}

because a pointer to S is stored inside S itself, so as soon as S gets
copied or moved, the delegate context pointer is no longer valid (or
else points to a different copy of the struct than the one it will be
called from).

If you need to store references to an aggregate inside itself, you
should be using a class instead.  Or be absolutely sure you allocate the
struct on the heap with `new`, AND never pass it around except by
reference (using pointers).


T

-- 
Almost all proofs have bugs, but almost all theorems are true. -- Paul Pedersen


  1   2   3   4   5   6   7   8   9   10   >