Re: Interfacing with basic C++ class

2022-09-28 Thread Ali Çehreli via Digitalmars-d-learn

On 9/28/22 12:57, Riccardo M wrote:

> class MyClass {
> public:
>  int field;
>  MyClass(int a) : field(a) {}

Make the following function 'virtual':

>  int add(int asd) {

virtual int add(int asd) {

I think the C++ class does not get a vptr without a virtual function and 
apparently D expects this.


>  final int add(int asd);

You don't need that 'final' anymore.

> This is a very simplified version of the dlang official example of
> interfacing with C++ classes.

The example there uses virtual functions. That must be the difference.

> I need to declare every class method as
> "final" otherwise I get  undefined references during linking. Is this
> expected behaviour?

Apparently, not with that added 'virtual'.

Ali




Re: to delete the '\0' characters

2022-09-23 Thread Ali Çehreli via Digitalmars-d-learn

On 9/23/22 11:37, Salih Dincer wrote:

> * character**S**
> * at the **END**
> * of the **STRING**

I think the misunderstanding is due to the following data you've posted 
earlier (I am abbreviating):


53 F6 6E 6D 65 64 65 6E 20 79 75 72 64 75 6D 75 6E 20 FC 73 74 FC 6E 64 
65 20 74 FC 74 65 6E 20 65 6E 20 73 6F 6E 20 6F 63 61 6B 0
4F 20 62 65 6E 69 6D 20 6D 69 6C 6C 65 74 69 6D 69 6E 20 79 131 6C 64 
131 7A 131 64 131 72 20 70 61 72 6C 61 79 61 63 61 6B 0 0 0 0


You must have meant there were multiple strings there (apparently on 
separate lines) but I assumed you were showing a single string with 0 
bytes inside the string. (Word wrap must have contributed to the 
misunderstanding.)


Ali

P.S. With that understanding, now I think searching from the end for the 
first non-zero byte may be faster than searching from the beginning for 
the first zero; but again, it depends on the data.





Re: to delete the '\0' characters

2022-09-22 Thread Ali Çehreli via Digitalmars-d-learn

On 9/22/22 14:31, Salih Dincer wrote:

> string splitz(string s)
> {
>import std.string : indexOf;
>auto seekPos = s.indexOf('\0');
>return seekPos > 0 ? s[0..seekPos] : s;
> }

If you have multiple '\0' chars that you will continue looking for, how 
about the following?


import std;

auto splitz(string s) {
return s.splitter('\0');
}

unittest {
auto data = [ "hello", "and", "goodbye", "world" ];
auto hasZeros = data.joiner("\0").text;
assert(hasZeros.count('\0') == 3);
assert(hasZeros.splitz.equal(data));
}

void main() {
}

Ali




Re: to delete the '\0' characters

2022-09-22 Thread Ali Çehreli via Digitalmars-d-learn

On 9/22/22 08:19, Ali Çehreli wrote:

> string noZeroes(string s)
> {
>  return s.byCodeUnit.filter!(c => c != '\0');
> }

That won't compile; the return type must be 'auto'.

Ali




Re: to delete the '\0' characters

2022-09-22 Thread Ali Çehreli via Digitalmars-d-learn

On 9/22/22 03:53, Salih Dincer wrote:
> Is there a more accurate way to delete the '\0' characters at the end of
> the string? I tried functions in this module:
> https://dlang.org/phobos/std_string.html

Just to remind, the following are always related as well because strings 
are arrays, which are ranges:


  std.range
  std.algorithm
  std.array

>r ~= c;

Stefan Koch once said the ~ operator should be called "the slow 
operator". Meaning, if you want to make your code slow, then use that 
operator. :)


The reason is, that operation may need to allocate memory from the heap 
and copy existing elements there. And any memory allocation may trigger 
a garbage collection cycle.


Of course, none of that matters if we are talking about a short string. 
However, it may become a dominating reason why a program may be slow.


I was going to suggest Paul Backus' solution as well but I may leave the 
array part out in my own code until I really need it:


string noZeroes(string s)
{
return s.byCodeUnit.filter!(c => c != '\0');
}

Now, a caller may be happy without an array:

auto a = s.noZeroes.take(10);

And another can easily add a .array when really needed:

auto b = s.noZeroes.array;

That may be seen as premature optimization but I see it as avoiding a 
premature pessimization because I did not put in any extra work there. 
But again, this all depends on each program.


If we were talking about mutable elements and the order of elements did 
not matter, then the fastest option would be to remove with 
SwapStrategy.unstable:


import std;

void main() {
auto arr = [ 1, 0, 2, 0, 0, 3, 4, 5 ];
arr = remove!(i => i == 0, SwapStrategy.unstable)(arr);
writeln(arr);
}

unstable works by swapping the first 0 that it finds with the last 
non-zero that it finds and continues in that way. No memory is 
allocated. As a result, the order of elements will not preserved but 
unstable can be very fast compared to .stable (which is the default) 
because .stable must move elements to the left (multiple times in some 
cases) and can be expensive especially for some types.


The result of the program above is the following:

[1, 5, 2, 4, 3]

Zeros are removed but the order is not preserved.

And very important: Don't forget to assign remove's return value back to 
'arr'. ;)


I know this will not work for a string but something to keep in mind...

Ali




Re: Why this function just decides to not call another function and do its thing instead?

2022-09-17 Thread Ali Çehreli via Digitalmars-d-learn

On 9/17/22 10:14, frame wrote:

On Saturday, 17 September 2022 at 15:04:48 UTC, solidstate1991 wrote:

And then instead just decides that the `localName` and `namespaceURI` 
pairs are not equal, and in those cases the Visual Studio debugger 
doesn't detect any entering into any of the `DOMString.equals` 
overrides, all while the debugger shows those strings are equal.


`opEquals` probably was not called if an operand was null. It seems that 
`Attr.localName` can return null.


Indeed. Copying from my /usr/include/dlang/dmd/object.d:

/++
Implementation for class opEquals override. Calls the class-defined 
methods after a null check.
Please note this is not nogc right now, even if your implementation 
is, because of
the typeinfo name string compare. This is because of dmd's dll 
implementation. However,

it can infer to @safe if your class' opEquals is.
+/
bool opEquals(LHS, RHS)(LHS lhs, RHS rhs) if (is(LHS : const Object) && 
is(RHS : const Object))

{
static if (__traits(compiles, lhs.opEquals(rhs)) && 
__traits(compiles, rhs.opEquals(lhs)))

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

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

if (!lhs.opEquals(rhs)) return false;

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

always identical. So, no opEquals needed during CTFE. */
{
return true;
}

// General case => symmetric calls to method opEquals
return rhs.opEquals(lhs);
}
else
{
// this is a compatibility hack for the old const cast behavior
// if none of the new overloads compile, we'll go back plain 
Object,

// including casting away const. It does this through the pointer
// to bypass any opCast that may be present on the original class.
return .opEquals!(Object, Object)(*cast(Object*) , 
*cast(Object*) );


}
}

Ali




Re: dub lint

2022-09-15 Thread Ali Çehreli via Digitalmars-d-learn

On 9/15/22 16:14, Christian Köstlin wrote:

> There is `dub run dscanner -- --defaultConfig` which creates a default
> config in `~/.config/dscanner/dscanner.ini` (for linux and osx).

Thanks! I love such features. It is so useful for a program to write out 
its configuration file. (My tools did that too.)


> interestingly `dub lint --help` shows two different options for 
`--config`:

>
> ```
> dub lint --help
> USAGE: dub lint [[@]] [] [--
> ]
> ..
> ..
>--config=VALUEUse the given configuration file.
> ..
> ..
>-c  --config=VALUEBuilds the specified configuration.

Neither of which is obvious to the newcommer at all. Not one bit! Even 
though I knew dscanner was the program 'dub lint' uses (perhaps because 
I noticed the message as it was being installed?) I did not think even 
once that 'dub lint's --config would refer to 'dscanner's config.


As a dub user, I wouldn't know to go to a random program's web site. 
Even 'dub lint' doesn't mention dscanner: 
https://dub.pm/commandline.html#lint


Ali



Re: dub lint

2022-09-15 Thread Ali Çehreli via Digitalmars-d-learn

On 9/15/22 15:04, Ali Çehreli wrote:

> Is there a way to silence specific 'dub lint' warnings?

Answering myself, I don't think it's possible but luckily my catching an 
Error was in unittests only so I can do either of the following to skip 
unittest code when linting:


a) Pass --skipTests to dscanner (what 'dub lint' runs behind the scenes) 
along with --styleCheck, which --skipTests requires


  dub lint -- --skipTests --styleCheck

b) Pass --styleCheck indirectly through 'dub lint', which has its own 
spelling for it :), but --skipTests is still required of course:


  dub lint --style-check -- --skipTests

Ali



Re: dub lint

2022-09-15 Thread Ali Çehreli via Digitalmars-d-learn

On 9/15/22 14:32, Ali Çehreli wrote:

> (However, like all linters it's not perfect but I still like having that
> power.)

The following code is flagged because it catches Error:

unittest
{
try
{
assert(false);
}
catch (Error)
{
// Cool...
}
}

[warn]: Catching Error or Throwable is almost always a bad idea.

Is there a way to silence specific 'dub lint' warnings? For example, the 
code above is actually similar to assertThrown!Error, which knows what 
it's doing. :)


  https://dub.pm/commandline.html#lint

Ali



dub lint

2022-09-15 Thread Ali Çehreli via Digitalmars-d-learn
I've always thought of dub as a package manager and a build tool. But it 
actually makes it easy to use other tools:


- dub lint: Runs some checks on your project. What I liked is how it 
removed the need to figure out how to install dscanner, which it uses 
behind the scenes. It installed dscanner and simply ran it. Cool... 
(However, like all linters it's not perfect but I still like having that 
power.)


- dub dustmite: I haven't actually tried this but dub's help with using 
dusmite sounds great.


Ali


Re: need help to translate C into D

2022-09-13 Thread Ali Çehreli via Digitalmars-d-learn

On 9/13/22 04:07, test123 wrote:
> On Tuesday, 13 September 2022 at 10:59:36 UTC, Dennis wrote:

>> Side node, you can use `immutable` instead of `__gshared const`, it
>> amounts to the same for global variables.
>
> because __enums_layout.ptr need to be part of other object, and this
> const ptr cloud be included in multi objects.

There may be valid reasons not to use 'immutable' but you can still do 
what you describe. There is an 'immutable' array below and its .ptr is 
being stored as 'const' inside objects of another struct.


struct S {
int i;
string s;
int[3] arr;
}

immutable S[] imm;

shared static this() {
// Initializing immutable at program initialization time:
imm ~= S(42, "hello", [1,2,3]);
imm ~= S(7, "world", [4,5,6]);
}

struct Other {
const S * ptr;
}

void main() {
auto o = Other(imm.ptr);
}

That works because 'const' can point to 'immutable' (and mutable and const).

Ali



Re: Function attribute best practices

2022-09-13 Thread Ali Çehreli via Digitalmars-d-learn

On 9/13/22 10:08, Paul Backus wrote:

> Here's my attempt, covering all the attributes found under
> [`MemberFunctionAttribute`][1] in the language spec:
>
> |Attribute|Affects |Inferred?|
> |-||-|
> |nothrow  |Function|Yes  |
> |pure |Function|Yes  |
> |@nogc|Function|Yes  |
> |@safe|Function|Yes  |
> |@system  |Function|Yes  |
> |@trusted |Function|No   |
> |@property|Function|No   |
> |@disable |Function|No   |
> |const|this|No   |
> |immutable|this|No   |
> |inout|this|No   |
> |shared   |this|No   |
> |return   |this|Yes  |
> |scope|this|Yes  |
>
> In general, attributes with a 'Yes' in the 'Inferred?' column should not
> be applied explicitly to functions that are subject to [attribute
> inference][2]. This includes functions defined inside templates, as well
> as nested functions and functions with an inferred return type (i.e.,
> `auto` functions).
>
> [1]: https://dlang.org/spec/function.html#MemberFunctionAttributes
> [2]: https://dlang.org/spec/function.html#function-attribute-inference

That is great! I think we can improve it with guidelines for when to 
write an attribute or not.


For example, carried over from C++, I have this guideline: "put const to 
as many member function as you can." That guideline makes the function 
more useful because I can call it on mutable, const, and immutable 
objects. Great... Programmers can understand that.


Now let's compare it to what the const attribute on a member function 
says (I did not find it in the spec; so making it up): "Makes the 'this' 
reference const." Although correct, it does not help the programmer.


Or... What does pure mean? Does it tell the outside world that the 
function is pure or does it require to be called from pure code? I put 
that here because e.g. 'immutable' on a member function kind of does 
that: It requires to be called on an immutable object. Ok, not a fair 
comparison because there is no "pure object" but still, these are 
thoughts that I think programmers have in mind. (I do. :) )


Ali



Re: Function attribute best practices

2022-09-13 Thread Ali Çehreli via Digitalmars-d-learn

On 9/12/22 09:39, Paul Backus wrote:

> Yes. Except for `@trusted`, explicit attributes on template code are a
> smell.

Except for 'const' as well because some templates are member functions. 
And 'const' on a member function cannot be left to inference because it 
happens to be a part of the type of the function, which can be overloaded.


Somebody needs to create a two dimensional table that shows what it 
means for each function attribute on a regular function, member 
function, and templates of those, and hopefully come up with some 
guidelines.


I started thinking about it but will not have time these coming days. :/

Ali



Re: Function attribute best practices

2022-09-12 Thread Ali Çehreli via Digitalmars-d-learn

On 9/12/22 11:29, Steven Schveighoffer wrote:

> So you are thinking about this the wrong way I believe.

Clearly.

> When you put `pure` on a template function, you are saying "only
> instantiations where this function can be pure are allowed".

Makes sense. I was trying to put as many attributes as possible, being 
proud like, "look: my function is pure, @nogc, etc."


Ali



Re: Function attribute best practices

2022-09-12 Thread Ali Çehreli via Digitalmars-d-learn

On 9/12/22 10:29, H. S. Teoh wrote:


write a unittest where you instantiate Foo with a
deliberately-impure type


Yes. A current on-topic thread on the difficulties of covering all 
corner cases:


  https://forum.dlang.org/thread/dmnfdqiplbldxkecp...@forum.dlang.org

Ali


Re: Function attribute best practices

2022-09-12 Thread Ali Çehreli via Digitalmars-d-learn

On 9/12/22 09:48, H. S. Teoh wrote:

>> @nogc nothrow pure @safe
>> unittest
>> {
>>  // ...
>> }
>>
>> No, it isn't because unless my unittest code is impure, I can't catch
>> my incorrect 'pure' etc. on my member functions.
> [...]
>
> Sure you can.  The `pure unittest` code obviously must itself be pure
> (otherwise it wouldn't compile). If Foo introduces impure behaviour,
> then the unittest, being pure, wouldn't be allowed to call Foo's impure
> methods, which is what we want.  What's the problem?

There was a problem until you and others put me straigth. :)

What I meant was

- if I put 'pure' etc. on my templatized code,

- and then tested with a 'pure' unittest,

I wouldn't know that the gratuitous use of my 'pure' on the member 
function was wrong. I would be fooling myself thinking that I smartly 
wrote a 'pure' member function and a 'pure' unittest and all worked. 
Wrong idea! :)


Now I know I must leave attributes as much to inference as possible.

Ali



Function attribute best practices

2022-09-12 Thread Ali Çehreli via Digitalmars-d-learn
The following range Foo is trying to be helpful by adding as many 
attributes as it can ('const' is missing because ranges cannot be 
'const' because at least popFront() needs to be mutable):


import std.algorithm;

struct Foo(R) {
R r;
int i;

bool empty() @nogc nothrow pure @safe scope {
return r.empty;
}

auto front() @nogc nothrow pure @safe scope {
return r.front;
}

auto popFront() @nogc nothrow pure @safe scope {
r.popFront();
}
}

auto foo(R)(R r) {
return Foo!R(r);
}

int count;

void main() {
[ 1, 2 ]
.map!((i) {
++count;// <-- Impure
return i;
})
.foo;
}

Of course there are compilation errors inside the member functions 
because e.g. r.front that it dispatches to is not pure (it touches the 
module variable 'count'):


  Error: `pure` function `deneme.Foo!(MapResult!(__lambda1, 
int[])).Foo.front` cannot call impure function 
`deneme.main.MapResult!(__lambda1, int[]).MapResult.front`


(Other attributes would cause similar issues if e.g. the lambda were @nogc.)

What are best practices here?

Is this accurate: Because Foo is a template, it should not put any 
attribute on member functions? Or only member functions that use a 
member that depends on a template parameter? And non-members that are 
templates?


It is scary because Foo works just fine until it is used with impure code.

Is putting function attributes on unittest blocks for catching such issues?

@nogc nothrow pure @safe
unittest
{
// ...
}

No, it isn't because unless my unittest code is impure, I can't catch my 
incorrect 'pure' etc. on my member functions.


Help! :)

Ali


Re: Why I get delegate when passing address of function?

2022-09-11 Thread Ali Çehreli via Digitalmars-d-learn

On 9/11/22 09:26, Ali Çehreli wrote:


// This combines a class instance (which is a pointer behind the scene)



     // Combine with the class object


In both places I meant "class variable".

Ali


Re: Why I get delegate when passing address of function?

2022-09-11 Thread Ali Çehreli via Digitalmars-d-learn

On 9/11/22 02:54, Injeckt wrote:

> And what I should do to pass non-static function?

You can combine your class object with other arguments and your thread 
function will know how to unwrap your class object to call its member 
function:


import std.stdio;

// I am not on Windows, so I am making it non-D another way
// Let's assume this is what the library wants from us
alias MyThreadFunc = uint function(void*);

// Let's assume this is what the library provides
extern (C)
void libraryCreateThread(MyThreadFunc func, void* param) {
writeln("The libraryCreateThread is starting our function");
func(param);
}

// This is my class
class C {
string s;

// This is the function I want to be called
void myClientThread(void* param) {
writeln("The desired member function is here");
writeln("the member: ", s);

// At this point we know the extra argument shoud be an
// int (that's why main used one)
auto arg = *cast(int*)param;
writeln("the extra argument: ", arg);
}
}

// We have to play along with what the library wants
// It wants a 'function', so here is one:
// (This could be a static member function)
uint myNonMemberThreadFunc(void* param) {
writeln("Our function is making the param useful...");

// See MyThreadArgs below
auto args = *cast(MyThreadArgs*)param;

writeln("... and calling our member function");
args.c.myClientThread(args.extraArg);

return 0;
}

// This combines a class instance (which is a pointer behind the scene)
// and any other argument
struct MyThreadArgs {
C c;
void* extraArg;
}

void main() {
auto c = new C();
c.s = "the class member";

// Assuming some extra argument
int mainArg = 42;

// Combine with the class object; this may have to be on the heap
auto args = MyThreadArgs(c, );

// Do what the library wants
libraryCreateThread(, cast(void*));
}

> Error: function `_server.Server.ClientThread(void* param)` is not
> callable using argument types `()`. too few arguments, expected `1`, got
> `0`

That looks like the same problem you had a couple of days ago: The name 
of the function is not a function pointer in D but is a call to it:


- foo: The same thing as foo()
- : 'function'

Ali



Re: Dictionary of Templated Functions

2022-09-10 Thread Ali Çehreli via Digitalmars-d-learn

On 9/10/22 15:35, jwatson-CO-edu wrote:

> So, my solution
> will be to construct a catch-all struct `Payload` and have that be my
> argument type from which various functions can draw the data of their
> choice.

Two Phobos features may be helpful there:

  https://dlang.org/phobos/std_sumtype.html

  https://dlang.org/phobos/std_variant.html

Ali



Re: Can you access the same classes from C++ and D and vise versa, or do the classes have to not form dependency cycle?

2022-09-10 Thread Ali Çehreli via Digitalmars-d-learn

On 9/10/22 13:04, Daniel Donnell wrote:
> https://dlang.org/spec/cpp_interface.html

At DConf, Manu indicated that that page is outdated and that D's C++ 
support is actually a lot better. He kind-of-promised to update that 
page but I doubt it happened yet if ever. :)


> one has to be compiled before the other, order depending on direction.

I don't think that's correct. The page is unfortunately unclear:

  "the first with a C++ compiler, the second with a D compiler"

could have better been written as

  "the C++ source file with a C++ compiler, and the D source file with 
a D compiler"


Ali



Re: Using .require for struct types

2022-09-10 Thread Ali Çehreli via Digitalmars-d-learn

On 9/10/22 09:33, Erdem Demir wrote:

>  DListOfA returnVal = temp.require("a", DListOfA());--> I wish I
> could use ref DListOfA here

But keeping a reference to a temporary would not work because the life 
of that temporary ends by the end of that expression (practically, at 
the semicolon).


An option is to allocate the object dynamically with new (and store 
DListOfA* in the associative array). Then the GC would keep it alive as 
long its pointer was in the associative arrray.


But a better option is to just forget about it because D already takes 
care of rvalues by blitting (bit-level copying) them by default. 
Everything just works... :) It is not expensive either. For example, 
your struct is very cheap to copy.


But I am probably missing the reason why you want a ref there. Perhaps 
there are even better options.


Ali



Re: Validate static asserts

2022-09-09 Thread Ali Çehreli via Digitalmars-d-learn

On 9/9/22 10:35, Dennis wrote:
> On Friday, 9 September 2022 at 16:41:54 UTC, Andrey Zherikov wrote:
>> What's about new `compileOutput` trait that returns compiler output?
>> ```d
>> static assert(__traits(compileOutput, {  }) == "message");
>> ```
>
> As a compiler dev, that sounds terrifying. It would make basically every
> change to dmd a breaking change.

For that very reason, I wrote the function 'assertErrorStringContains()' 
a couple of days ago to ensure *my* strings were in the output:


A precondition:

void test_1(int i)
in (i > 0, fooError("The value must be positive", i, 42))
{
// ...
}

A unit test that ensures it fails and checks string pieces appear in the 
output:


/*
The .msg text of the error contains both the error string and 
the data

that is included in the error.
*/
assertErrorStringContains(() => test_1(-1), [ "The value must be 
positive",

  "-1, 42" ]);
Here is assertErrorStringContains:

// Assert that the expression throws an Error object and that its 
string

// representation contains all expected strings.
void assertErrorStringContains(void delegate() expr, string[] expected)
{
bool thrown = false;

try
{
expr();

}
catch (Error err)
{
thrown = true;

import std.algorithm : any, canFind, splitter;
import std.conv : to;
import std.format : format;

auto lines = err.to!string.splitter('\n');
foreach (exp; expected)
{
assert(lines.any!(line => line.canFind(exp)),
   format!"Failed to find \"%s\" in the output: 
%-(\n  |%s%)"(

   exp, lines));
}
}

assert(thrown);
}

Ali



Re: Validate static asserts

2022-09-09 Thread Ali Çehreli via Digitalmars-d-learn

On 9/9/22 07:35, Andrey Zherikov wrote:

> might not compile due to many different reasons

I faced a related situation recently: My error string generation was 
buggy, which taught me that the compiler does not even compile the 
string part of 'static assert' in the 'true' case.


The following program compiles! :)

void main() {
static assert (true, "hello" / WAT);
}

> Is there a way to validate static asserts in unit tests?

I added and removed '&& false' to every 'static assert' condition 
manually one by one. :/


Perhaps a new compiler switch can compile every 'static assert' with an 
automatic 'false' and dump all their text to the output.


Ali



Re: Storing a lambda alongside type-erased data

2022-09-08 Thread Ali Çehreli via Digitalmars-d-learn

On 9/8/22 08:02, Paul Backus wrote:

> This is actually pretty much exactly what VariantN does

Great information, thanks! I am slowly getting up there. :)

Ali



Storing a lambda alongside type-erased data

2022-09-07 Thread Ali Çehreli via Digitalmars-d-learn
I am sure nothing is new here and I may have thought of this before but 
it was a revelation today. :)


I've been trying to come up with a way of storing arbitrary number of 
objects of arbitrary types, which means I would be using a ubyte array.


But then how do I use the data later without needing to remember its 
type perhaps with TypeInfo? I first considered registering data up front 
with something like


  SumType!(Tuple(int, string, double),
   Tuple(S, char))

but I couldn't make it work and it wasn't useful having to register 
valid sets of data like that.


I looked at how std.variant.VariantN prints the correct type and failed 
to understand the magic there. :(


Then I came up with storing a lambda that is created when the exact type 
is known. The following simple variant can carry arbitrary set of data 
because the data is provided as sequence template parameters (aka variadic).


Note that set() member function is @nogc because the data is placed in 
an existing ubyte array. (That was the main motivation for this design.) 
(I left notes about 3 bugs in there, which can all be taken care of.)


Then the stored lambda is used to print the data. (I am sure the lambda 
can do other things.) I chose 'function' in order to be @nogc. When not 
required, it could be a 'delegate' as well.


import std; // Sorry :(

struct V_(size_t size)
{
// This is where the data will reside; we have no idea on
// what actual types of data will be used.
ubyte[size] mem;

// This is the lambda that remembers how to use the data
// (printing to an output sink in this case.)
void function(void delegate(in char[]), const(ubyte)*) dataToStr;

// We can set any data into our data buffer
void set(Args...)(Args args) @nogc nothrow pure {
// Thank you, Tuple! :)
alias Data = Tuple!Args;

// Place the tuple of arguments
//
// BUG 1: Must consider alignment of Data
// BUG 2: Must check that size is sufficient
// BUG 3: The destructor of old data should be run
//(optionally?)
emplace(cast(Data*)(mem.ptr), Data(args));

// This is the interesting bit: Storing the lambda that
// knows how to print this type.
dataToStr = (sink, ptr) {
// Cast back to the actual type. We know the type here.
auto d = cast(Data*)(ptr);
static foreach (i; 0 .. args.length) {
if (i != 0) {
sink(", ");
}
sink((*d)[i].to!string);
}
};
}

void toString(scope void delegate(in char[]) sink) const {
dataToStr(sink, mem.ptr);
}
}

// A convenience function to avoid needing to specify the
// template parameter. (The syntax is noisy otherwise.)
auto V(size_t size = 1024)() {
return V_!size();
}

void main() {
// Start with an empty variant
auto v = V();

// Store some data in it
v.set(42, "hello", 2.5);
writeln(v);

// Now set different types of data
struct S {
int i;
}
v.set(S(7), 'a');
writeln(v);
}

Ali


Re: Error "Unexpected '\n' when converting from type LockingTextReader to type int"

2022-09-07 Thread Ali Çehreli via Digitalmars-d-learn

On 9/7/22 16:24, Synopsis wrote:

> a- What is the difference with this syntax with the exclamation mark?
> ```readf!"%s\n"(f1.num);```

That's the templated version, which is safer because it checks at 
compile time (important distinction) that the arguments and the format 
specifiers do match.


> b- Do I need to put ```/n``` in every readf statement?

Another option is to use a space character, which reads and skips any 
number of any whitespace character. I have written something about that 
here:


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

And this one talks about readln, which may be more suitable in some cases:

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

And there is formattedRead:

  http://ddili.org/ders/d.en/strings.html#ix_strings.formattedRead

> Forgive me if I'm asking silly questions.

There is never a silly question. If a question came up, it is as 
legitimate as it gets.


And welcome to programming! :)

Ali



Re: Comparing slices with std.variant.Algebraic

2022-09-05 Thread Ali Çehreli via Digitalmars-d-learn

On 9/5/22 01:58, anonymouse wrote:

> array [1.7, 3.7, 5.7, 7.7, 9.7] in both cases, which is what is being
> asserted by those two lines.

None of those values can be represented precisely in a floating point 
type. Without looking at the code, I wonder whether the tests will pass 
if you can manage to use the following values instead, which can be 
represented precisely:


  [1.5, 3.5, 5.5, 7.5, 9.5]

Ali



Re: Why do failed contracts don't dump stack backtrace in unittests?

2022-09-04 Thread Ali Çehreli via Digitalmars-d-learn

On 9/4/22 09:35, Paul Backus wrote:


     // TODO: omit stack trace only if assert was thrown
     // directly by the unittest.


Thank you but I mean... :) I can understand removing a backtrace from 
the eyes of an end user but the consumer of a unittest output is a 
developer, no?


Ali


Why do failed contracts don't dump stack backtrace in unittests?

2022-09-04 Thread Ali Çehreli via Digitalmars-d-learn
The program output is different whether an Error is thrown from main or 
from the unittest block:


void foo(string s)
in (s != "hello") {
}

unittest {
  foo("hello");  // No stack backtrace
}

void main() {
  foo("hello");  // Yes stack backtrace
}

Ali


Re: Best practice for dub registry package and module names

2022-09-03 Thread Ali Çehreli via Digitalmars-d-learn

On 9/3/22 20:39, Ali Çehreli wrote:

For example, there is fixedsizearray, which does not belong to any package:

  https://code.dlang.org/packages/fixedsizearray

On the other hand, arsd-official:minigui does have a package. (And that 
answers a question: Dash character is acceptable in package and module 
names.)


  https://code.dlang.org/packages/arsd-official%3Aminigui

How does that work? When the following dependency added to a user's project,

  "arsd-official:minigui": "~>10.9.1"

does dub pull the entirety of arsd-official and then use minigui module 
from it? I think so, because minigui has dependencies to the same 
package which are (I think) not specifiable in dub.


So, if I register the C package, B and A will be available under it and 
the users can use A and B. I think I need to get used to the feeling of 
wastefulness for pulling the entire package. :/


Ali


Re: Best practice for dub registry package and module names

2022-09-03 Thread Ali Çehreli via Digitalmars-d-learn

On 9/3/22 20:04, rikki cattermole wrote:
> This slightly smells, single module dub packages.
>
> What does each module do?

The other issue is NIH because some of their functionality already 
exists. :/


A: Block of elements

B: Expanding circular buffer

C: Cache of elements

I would like to register only C. However, B and A can be useful 
individually as well.


My conflict stems from the fact that e.g. 'import block;' may collide 
with the user's own 'block'. There better be some namespacing, no?


Ali



Best practice for dub registry package and module names

2022-09-03 Thread Ali Çehreli via Digitalmars-d-learn
Let's say I have three modules that work together, which I want to 
register on dub: A, B, and C.


Although the most interesting one is C and A and B are used in its 
implementation, A and B can be registered individually as well and be 
used as C's dependencies.


I know package-less modules are more prone to name collisions; so I 
would like to give package names to these three modules.


Should the package name be the same as each module? a.a, b.b, and c.c?

Should the package be the author's name: acehreli.a, acehreli.b, and 
acehreli.c?


Should they somehow reflect what they do: storage.a, buffer.b, and cache.c?

What about module names? If the type is 'struct MyCache', should the 
module name be mycache, or my_cache, or my-cache?


What else?

Thank you,
Ali


Re: Error while generate DNA with uniform()

2022-09-03 Thread Ali Çehreli via Digitalmars-d-learn

On 9/3/22 14:18, Salih Dincer wrote:

>uniform!"[]"(DNA.min, DNA.max);

Even cleaner:

  uniform!DNA()

:)

Ali



Re: Error while generate DNA with uniform()

2022-09-03 Thread Ali Çehreli via Digitalmars-d-learn

On 9/3/22 07:25, Steven Schveighoffer wrote:

> There is probably a bug in generate when the element type is an `enum`
> which somehow makes it const.

Yes, Generator is missing an Unqual:

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

Salih had asked:

>> Can we solve this issue with our own `generate()` structure?

Yes, I did the following to determine that adding Unqual was a solution:

- Copy generate() functions to your source file,

- Copy the Generator struct to your source file,

- Edit the definition of Generator's elem_ member as I hinted in the bug.

Ali



Re: Constructors not working

2022-09-02 Thread Ali Çehreli via Digitalmars-d-learn
I forgot to say that you don't need to write a constructor for most 
structs because Time's constructor-generated default constructor works 
like yours and with default arguments:


struct Time {
  public int hours, minutes, seconds;

  // No constructor needed here.

  // Note 'return this;' as the last statement would be
  // mimicing how fundamental types like 'int'
  // work. However, I am getting the following warning when
  // I do that:
  //
  //   Deprecation: returning `this` escapes a reference to
  //   parameter `this` perhaps annotate the function with
  //   `return`
  //
  // For simplicity, I will just return void in this code.
  //
  void opAssign(int secos) {
assert(secos <= 86_400);
hours = secos / 3600;
minutes = (secos % 3600) / 60;
seconds = secos % 60;
  }
}

import std.stdio;

void main() {
  auto time = Time(360);
  time = 12_345;
  writeln(time);
  readln;
}

Ali



Re: Constructors not working

2022-09-02 Thread Ali Çehreli via Digitalmars-d-learn

On 9/2/22 11:35, Svyat wrote:

>  Time time = 360;

It seems to be more idiomatic to write it like this:

  auto time = Time(360);

Or const, immutable, etc.

  const time = Time(360); // Now un-assignable

But you would get the same compilation error. So, one way to work with 
it is to use default constructor arguments:


  this(int h, int m = 0, int s = 0)

Then it would work with just 360.

> .\testfortime.d(6):too few arguments, expected `3`, got `1`"

At least that one is helpful. There are much more cryptic error messages 
out there. :)


Ali



Re: Convert array of tuples into array of arrays.

2022-08-31 Thread Ali Çehreli via Digitalmars-d-learn

On 8/31/22 07:34, musculus wrote:
> Hi. I have an array of tuples that I would like to convert to an array
> of arrays.

I misunderstood as well and wrote the following program which makes 
separate arrays. You can make an array of arrays from those with the 
following syntax:


  auto arrayOfArrays = [ keys, values ];

Then I wrote a more general program after this first one:

// Compiles slow but is convenient
import std;

auto makeTestTuple(int i) {
  return tuple!("key", "value")((i * 2).to!string,
(double(i) / 10).to!string);
}

void main() {
  auto tuples = iota(10)
.map!makeTestTuple
.array;

  string[] keys;
  string[] values;

  writeln("Imperative:");

  foreach (t; tuples) {
keys ~= t.key;
values ~= t.value;
  }

  writeln(keys);
  writeln(values);

  writeln("Alternative:");
  keys = tuples.map!(t => t.key).array;
  values = tuples.map!(t => t.value).array;
  writeln(keys);
  writeln(values);

  writeln("More generic:");
  keys = tuples.memberArray!"key";
  values = tuples.memberArray!"value";
  writeln(keys);
  writeln(values);
}

auto memberArray(string member, T)(T[] tuples) {
  return tuples.map!(t => mixin("t." ~ member)).array;
}

Here is the second program to have fun and "competitive advantage" with 
D. (That phrase came up recently, so I remembered it here. :) )


// Compiles slow but is convenient
import std;

auto makeTestTuple(int i) {
  return tuple!("key", "value", "somethingElse")(
(i * 2).to!string,
(double(i) / 10).to!string,
i * i);
}

mixin template matchingMember(string name, T) {
  mixin (T.stringof ~ "[] " ~ name ~ ';');
}

template TupleMemberArrays(T) {
  alias types = T.Types;
  alias fieldNames = T.fieldNames;
  enum memberCount = types.length;

  struct TupleMemberArrays {
static foreach (i; 0 .. memberCount) {
  mixin matchingMember!(fieldNames[i], types[i]);
}

this(T[] tuples) {
  foreach (t; tuples) {
static foreach (i; 0 .. memberCount) {
  mixin (format!q{
  %s ~= t.%s = t[%s];
}(fieldNames[i], fieldNames[i], i));
}
  }
}
  }
}

void main() {
  auto tuples = iota(10)
.map!makeTestTuple
.array;

  alias S = TupleMemberArrays!(ElementType!(typeof(tuples)));
  auto s = S(tuples);
  writeln(s.key);
  writeln(s.value);
  writeln(s.somethingElse);
}

That second program defines a type that matches the members of a tuple. 
Given a tuple with member names "key", "value", and "somethingElse"; and 
types string, string, int; it generates a struct similar to the following:


struct YourAliasHere {
  string[] key;
  string[] value;
  int[] somethingElse;
}

Limitation: That implementation uses field names, which not all tuples 
use. But it can be changed to generate names file field0, field1, etc. 
when needed.


Ali



Re: is it possible synchronized(null) ? i.e NO-OP

2022-08-26 Thread Ali Çehreli via Digitalmars-d-learn
On the main forum, Paul Backus proposed a nested function as well as a 
scoped lock.


On 8/26/22 10:13, mw wrote:

>Object lock = (a particular condition) ? realLock : null;

And I want to point out that "a particular condition" must not change 
between the check above and the following synchronized statement.


>
>synchronized(lock) {
>  // lots of complex code block here
>}

Ali



Re: Is it possible to return mutable and const range from a single method?

2022-08-22 Thread Ali Çehreli via Digitalmars-d-learn

On 8/22/22 09:36, realhet wrote:

> It gives the protection I was needed but is it possible to make this
> prettier?

>  auto allParents(){
>struct ParentRange{
>  A act;
>  @property bool empty() const{ return act is null; }
>  @property A front() { return act; }
>  void popFront(){ act = act.getParent; }
>}
>return ParentRange(getParent);
>  }
>
>  auto allParents()const {
>struct ConstParentRange{
>  A act;
>  @property bool empty() const{ return act is null; }
>  @property const(A) front() inout { return act; }
>  void popFront(){ act = act.getParent; }
>}
>return ConstParentRange(cast()getParent);
>  }

In other words, is it possible to combine the double implementation 
above? The following looks at typeof(this) to pick the type. My test 
asserts seem to pass:


import std;

class A{
inout(A) getParent() inout{ return null; }

void nonConstMemberFunc() {}
void constMemberFunc() const {}

this(A p){
}
}

class B : A{
A parent;

override inout(A) getParent() inout{ return parent; }

struct ConstOrMutable(T) {
  // This alias is not strictly necessary; 'static if'
  // could define 'act' instead.
  static if (is (T == const)) {
alias X = const(A);

  } else {
alias X = A;
  }

  X act;
  @property auto empty() const { return act is null; }
  @property auto front() { return act; }
  void popFront() { act = act.getParent; }
}

auto allParents() inout {
  return ConstOrMutable!(typeof(this))(cast()getParent());
}

this(A p){
super(p);
parent = p;
}
}

auto test(inout A a, void delegate(inout A) fun){
auto p = a.getParent;
fun(p);
}

void main()
{
auto a = new A(null);
auto b = new B(a);

assert( __traits(compiles, b.constMemberFunc()));
assert( __traits(compiles, b.nonConstMemberFunc()));

const c = b;
assert( __traits(compiles, c.constMemberFunc()));
assert(!__traits(compiles, c.nonConstMemberFunc()));
}

Ali



Re: typeof(func!0) != typeof(func!0())

2022-08-21 Thread Ali Çehreli via Digitalmars-d-learn

On 8/21/22 21:39, Andrey Zherikov wrote:

>  alias type = typeof(U().func!0);
>  pragma(msg, type);  // pure nothrow @nogc ref @safe U()
> return

This is where the @property keyword makes a difference:

@property auto ref func(int i)() { return this; }

Now U().func!0 will be a call in your expression. But @property is not 
recommended (deprecated?).


But I think std.traits.ReturnType is more explicit and does work in this 
case:


import std.traits;
alias type = ReturnType!(U().func!0);

Ali



Re: Recommendation for parallelism with nested for loops?

2022-08-18 Thread Ali Çehreli via Digitalmars-d-learn

On 8/18/22 18:49, Shriramana Sharma wrote:
> Hello. I want to parallelize a computation which has two for loops

An option is to add tasks individually but I am not sure how wise doing 
this and I don't know how to determine whether all tasks are completed.


In any case, Roy Margalit's DConf 2022 presentation is very much on 
topic. :)


  http://dconf.org/2022/index.html#roym

And the following program cannot show any benefit because the tasks are 
so short.


import std.stdio;
import std.parallelism;
import std.conv;

enum I = 1_000;
enum J = 1_000;

void main() {
  auto results = new int[I * J];

  // In case you want a new TaskPool:
  // auto tp = new TaskPool(totalCPUs);
  // (And use tp. below instead of taskPool.)

  foreach (i; 0 .. I) {
foreach (j; 0 .. J) {
  taskPool.put(task!foo(i, j, results));
}
  }

  // WARNING: I am not sure whether one can trust the results are
  //  ready yet. (?)
  //
  // parallel() does call yieldForce() on each task but we don't seem
  // to have that option for tasks that are .put() into the pool. (?)

  enum toPrint = 10;
  writeln(results[0..toPrint]);
  writeln("[...]");
  writeln(results[$-toPrint..$]);
}

void foo(size_t i, size_t j, int[] results) {
  results[i * J + j] = to!int(i * J + j);
}

Ali



Re: In-place extension of arrays only for certain alignment?

2022-08-17 Thread Ali Çehreli via Digitalmars-d-learn

On 8/17/22 19:27, Steven Schveighoffer wrote:
> On 8/17/22 10:09 PM, Ali Çehreli wrote:
>>  > IIRC, your data does not need to be sequential in *physical memory*,
>>  > which means you can use a ring buffer that is segmented instead of
>>  > virtually mapped, and that can be of any size.
>>
>> I thought about that as well. But I would like the sizes of blocks
>> (Appenders?) be equal in size so that opIndex still can provide O(1)
>> guarantee. (Compute the block + an offset.)
>
> It's still O(1). You only have 2 slices to worry about.

Sometimes 2... I wanted to leave the sliding window width dynamic.

So, there will be M buffers, not 2. If their lengths are not equal, 
opIndex must be O(M). M is expected to be small but still...


M buffers of 'pageSize - (meta data).sizeof' each.

BeerConf... Sure... :)

Ali



Re: In-place extension of arrays only for certain alignment?

2022-08-17 Thread Ali Çehreli via Digitalmars-d-learn

On 8/17/22 18:31, Steven Schveighoffer wrote:

> 1. I highly recommend trying out the ring buffer solution to see if it
> helps. The disadvantage here is that you need to tie up at least a page
> of memory.

I started to think holding on to multiple pages of memory should not 
matter anyway. If really needed, an array of Appenders could be used; 
when really really needed, they may come from a free list.


Aside: I looked at Appender's implementation and saw that extending is 
one of its concerns as well.


> 2. All my tests using the ring buffer showed little to no performance
> improvement over just copying back to the front of the buffer. So
> consider just copying the data back to the front of an already allocated
> block.

That makes sense as well. One worry would be types with copy 
constructors. (I am not sure whether D is still a language where structs 
can freely be moved around.)


> IIRC, your data does not need to be sequential in *physical memory*,
> which means you can use a ring buffer that is segmented instead of
> virtually mapped, and that can be of any size.

I thought about that as well. But I would like the sizes of blocks 
(Appenders?) be equal in size so that opIndex still can provide O(1) 
guarantee. (Compute the block + an offset.)


>
> -Steve

Ali



Re: In-place extension of arrays only for certain alignment?

2022-08-17 Thread Ali Çehreli via Digitalmars-d-learn

On 8/16/22 19:33, Steven Schveighoffer wrote:

> Everything in the memory allocator is in terms of pages. A pool is a
> section of pages. The large blocks are a *multiple* of pages, whereas
> the small blocks are pages that are *divided* into same-sized chunks.

Thank you. I am appreciating this discussion a lot.

> When you want to allocate a block, if it's a half-page or less, then it
> goes into the small pool, where you can't glue 2 blocks together.

That's how it should be because we wouldn't want to work to know which 
blocks are glued.


>>  > The reason why your `bad` version fails is because when it must
>>  > reallocate, it still is only allocating 1 element.

I will get back to this 1 element allocation below.

>> That part I still don't understand. The same block of e.g. 16 bytes
>> still has room. Why not use that remaining portion?
>
> It does until it doesn't. Then it needs to reallocate.

I think my problem was caused by my test data being 16 bytes and (I 
think) the runtime picked memory from the 16-byte pool without any hope 
of future growth into adjacent block.


Using a 16-byte block sounds like a good strategy at first because 
nobody knows whether an array will get more than one element.


However, if my guess is correct (i.e. the first element of size of 
16-bytes is placed on a 16-byte block), then the next allocation will 
always allocate memory for the second element.


One might argue that dynamic arrays are likely to have more than a 
single element, so the initial block should at least be twice the 
element size. This would cut memory allocation by 1 count for all 
arrays. And in my case of 1-element arrays, allocation count would be 
halved. (Because I pay for every single append right now.)


Of course, I can understand that there can be applications where a large 
number of arrays (e.g. a 2D array) may have zero-elements or 
one-element, in which case my proposal of allocating the first element 
on a e.g. 32-byte block would be wasteful.


I think such cases are rare and we incur 1 extra allocation penalty for 
all arrays for that strategy.


> Maybe some ASCII art? `A` is "used by the current slice", `x` is
> "allocated, but not referenced by the array". `.` is "part of the block
> but not used (i.e. can grow into this)". `M` is "metadata"
>
> ```d
> auto arr = new ubyte[10];  //   AA.. ...M
> arr = arr[1 .. $]; // xAAA  AA.. ...M
> arr ~= 0;  // xAAA  AAA. ...M
> arr ~= 0;  // xAAA   ...M
> arr = arr[3 .. $]; //    ...M
> arr ~= cast(ubyte[])[1, 2, 3]; //    AAAM // full!
> arr ~= 1;  //    ...M // reallocated!
> arr.ptr has changed
> ```

That all makes sense. I didn't think the meta data would be at the end 
but I sense it's related to the "end slice", so it's a better place 
there. (?)


> Metadata isn't always stored. Plus, it's optimized for the block size.
> For example, any block that is 256 bytes or less only needs a single
> byte to store the "used" space.

That's pretty interesting and smart.

> What is your focus? Why do you really want this "optimization" of gluing
> together items to happen?

This is about what you and I talked about in the past and something I 
mentioned in my DConf lightning talk this year. I am imagining a 
FIFO-like cache where elements of a source range are stored. There is a 
sliding window involved. I want to drop the unused front elements 
because they are expensive in 2 ways:


1) If the elements are not needed anymore, I have to move my slice 
forward so that the GC collects their pages.


2) If they are not needed anymore, I don't want to even copy them to a 
new block because this would be expensive, and in the case of an 
infinite source range, impossible.


The question is when to apply this dropping of old front elements. When 
I need to add one more element to the array, I can detect whether this 
*may* allocate by the expression 'arr.length == arr.capacity' but not 
really though, because the runtime may give me adjacent room without 
allocation. So I can delay the "drop the front elements" computation 
because there will be no actual copying at this time.


But the bigger issue is, because I drop elements my array never gets 
large enough to take advantage of this optimization and there is an 
allocation for every single append.


> https://dlang.org/phobos/core_memory.html#.GC.extend

Ok, that sounds very useful. In addition to "I can detect when it *may* 
allocate", I can detect whether there is adjacent free room. (I can ask 
for just 1 element extension; I tested; and it works.) (I guess this 
GC.extend has to grab a GC lock.)


However, for that to work, I seem to need the initial block pointer that 
the GC knows about. (My sliding array's .ptr not work, so I have to save 
the initial arr.ptr).


Conclusion:

1) Although understanding the inner workings of the runtime is 

Re: Programs in D are huge

2022-08-17 Thread Ali Çehreli via Digitalmars-d-learn

On 8/17/22 09:28, Diego wrote:

> I'm writing a little terminal tool, so i think `-betterC` is the best
> and simple solution in my case.

It depends on what you mean with terminal tool bun in general, no, full 
features of D is the most useful option.


I've written a family of programs that would normally be run on the 
terminal; I had no issues that would warrant -betterC.


Ali



Re: In-place extension of arrays only for certain alignment?

2022-08-16 Thread Ali Çehreli via Digitalmars-d-learn

Thank you for the quick response.

On 8/16/22 12:31, Steven Schveighoffer wrote:
> On 8/16/22 2:11 PM, Ali Çehreli wrote:
>> Related to my DConf 2022 lightning talk, I am noticing that D
>> runtime's in-place array extension optimization is available only for
>> array data that are at certain memory alignments.
>>
>
> No, it's based on 2 factors:
>
> 1. Is it a page-size-or-greater block?

I assume the length of the new block.

> 2. Is there a free page after it?

Makes sense.

> The reason why your `bad` version fails is because when it must
> reallocate, it still is only allocating 1 element.

That part I still don't understand. The same block of e.g. 16 bytes 
still has room. Why not use that remaining portion?


Here is a simpler test with better-than-expected results. Array c is 
what I want to do. In this test it works and I don't even need to call 
assumeSafeAppend() (this must be what you call "end slice"):


import std.stdio;

void main() {
  ubyte[] a;
  a ~= 0;
  a.length = 0;
  a.assumeSafeAppend(); // Needed
  assert(a.capacity == 15);

  // Essentially, the same as above
  ubyte[] b;
  b ~= 0;
  b = b[0..0];
  b.assumeSafeAppend();// Needed
  assert(b.capacity == 15);

  ubyte[] c;
  c ~= 0;
  c = c[1..$];
  // c.assumeSafeAppend();
  assert(c.capacity == 14);
}

> metadata (e.g. typeinfo for destruction and append capacity).

I think it is 16 bytes total (on 64 bits): void* + size_t and I see this 
when I print .ptr: The change is always 0x10.


> Note that once you reach page size, the optimization can happen, *even
> if you are only appending to an end slice*. Here's something to try:
> when the capacity is less than the "magic" number of elements, `reserve`
> that number of elements. Then the "drop one element each loop" should
> use the optimization.

.reserve sounds promising but it will sometimes allocate memory and move 
elements even if I will not really need e.g. more than just one more 
element. (In my case, I may not know how many will be needed.) In other 
words, I really don't know how much to reserve.


What I seem to need is this function:

void increaseCapacityWithoutAllocating(T)(ref T[] arr) {
  // ...
}

Only the runtime seems to be able to implement that function. Can I call 
something in the runtime similar to how assumeSafeAppend() calls 
_d_arrayshrinkfit() in object.d?


>
> -Steve

Ali



In-place extension of arrays only for certain alignment?

2022-08-16 Thread Ali Çehreli via Digitalmars-d-learn
Related to my DConf 2022 lightning talk, I am noticing that D runtime's 
in-place array extension optimization is available only for array data 
that are at certain memory alignments.


I used the following program to test it. In addition to repeatedly 
adding an element to an array,


- 'version = neither' does not drop any element (this is "good" as well)

- 'version = bad' case drops the front element (a moving window of 1)

- 'version = good' case drops elements only when element data will hit a 
certain alignment value.


Is this expected?

import std.stdio;
import std.range;

// PLEASE UNCOMMENT ONLY ONE:
// version = bad;// No in-place extension
// version = good;   // In-place extension happens
// version = neither;// In-place extension happens

mixin assertSingleVersionOf!("bad", "good", "neither");

void main() {
  struct S {
ubyte[4] data;  // Try different reasonable sizes.
// For example, 5 will not work even
// for the "good" case.
  }

  S[] arr;

  foreach (i; 0 .. 100_000) {
const oldCap = arr.capacity;
const oldPtr = arr.ptr;

arr ~= S.init;

if (arr.capacity != oldCap) {
  // The array needed to be extended...
  if (arr.ptr == oldPtr) {
// ... but the pointer did not change
writefln!"In-place extension -- element: %,s  capacity: %,s -> 
%,s  ptr: %s"(

  i, oldCap, arr.capacity, arr.ptr);
  }
}

version (neither) {
  // Do not remove any element; just extend
}

version (bad) {
  // Dropping 1 element inhibits in-place extension
  // (Many values other than 1 will inhibit as well.)
  arr = arr[1..$];

  // Even this does not help
  arr.assumeSafeAppend();
}

version (good) {
  // Dropping front elements equaling 2048 bytes works.
  // (Likely a GC magic constant.)

  enum magic = 2048;
  enum elementsPerPage = magic / S.sizeof;

  if (arr.length == elementsPerPage) {
arr = arr[elementsPerPage..$];
  }
}
  }
}

// A useful template that has nothing to do with this problem.
mixin template assertSingleVersionOf(args...) {
  import std.format : format;

  static assert (1 >= {
size_t count = 0;
static foreach (arg; args) {
  static assert (is (typeof(arg) == string));
  mixin (format!q{
version (%s) {
  ++count;
}
  }(arg));
}
return count;
  }(), format!"Please pick only one or none of %(%s, %)"([args]));
}

Ali


Re: Exercise at end of Ch. 56 of "Programming in D"

2022-08-14 Thread Ali Çehreli via Digitalmars-d-learn

On 8/14/22 19:23, Ali Çehreli wrote:

>  // BUG DUE TO WISHFUL THINKING:
>  override size_t toHash() const {
>/* Since the 'points' member is an array, we can take
> * advantage of the existing toHash algorithm for
> * array types. */
>return typeid(points).getHash();

Thinking more about this, I think the above would still work if the 
Point type had a toHash() function that also ignored the color member. 
Adding just the following function makes the code work:


class Point {
  int x;
  int y;
  Color color;

  // ...

  override size_t toHash() const {
return x + y;
  }
}

The book is simply forgetting to show that function. (Otherwise, I never 
put any code without testing.)


WARNING: Hash functions can be very tricky. I have a strong feeling that 
adding two integers is not an efficient one.


Ali



Re: Exercise at end of Ch. 56 of "Programming in D"

2022-08-14 Thread Ali Çehreli via Digitalmars-d-learn

On 8/14/22 18:47, johntp wrote:
> I'm using DMD64 D Compiler v2.100.0 on linux mint.

Same version here.

> I copied the author's
> solution and got the same thing.

Wow! Are people actually working on those? :)

At first, I couldn't even get the code to compile due to 
const-correctness issues with opCmp. :/ I used the following cast():


  foreach (i, point; points) {
  immutable comparison = (cast()point).opCmp(rhs.points[i]);
  // ...
  }

> Is there an errata page for the book?

No. It is supposed to be corrected as mistakes are discovered. The 
online version should be the most recent.


The bug was with trying to implement that unnatural "ignore the color" 
in the comparison logic but then toHash was taking advantage of existing 
array hashing code, which had no idea of the programmer's requirement:


class Point {
  int x;
  int y;
  Color color;

  // IGNORES COLOR:
  override bool opEquals(Object o) const {
const rhs = cast(const Point)o;
return rhs && (x == rhs.x) && (y == rhs.y);
  }

  // ...
}

class TriangularArea {
// BUG DUE TO WISHFUL THINKING:
override size_t toHash() const {
  /* Since the 'points' member is an array, we can take
   * advantage of the existing toHash algorithm for
   * array types. */
  return typeid(points).getHash();
}

// ...
}

Here is a very inefficient implementation that still relies on existing 
array hashing functionality but after creating an array that does not 
contain the color field. I am pretty sure sort(tuples) is needed but at 
least the example works without it as well:


  override size_t toHash() const {
auto tuples = points[].map!(p => tuple(cast()p.x, cast()p.y)).array;
sort(tuples);
return () @trusted {
  return typeid(tuples).getHash();
}();
  }

Writing it in an efficient way is left as en excercise because the 
auther is too lazy to learn how to do it. :p


In case it's not clear, toHash() creates a new array which does not 
contain any color information and then sorts it and then needs to use 
the @trusted trick because toHash is @safe (apparently).


Ali



Re: chain of exceptions, next method

2022-08-13 Thread Ali Çehreli via Digitalmars-d-learn

On 8/13/22 15:59, kdevel wrote:
> Quote from `src/druntime/src`:
>
> ```
>  /**
>   * Returns:
>   * A reference to the _next error in the list. This is used when 
a new

>   * $(D Throwable) is thrown from inside a $(D catch) block. The
> originally
>   * caught $(D Exception) will be chained to the new $(D Throwable)
> via this
>   * field.
>   */
>  @property inout(Throwable) next() @safe inout return scope pure
> nothrow @nogc { return nextInChain; }
>
> ```

This automatic "combining" of exceptions happens for cleanup code like 
scope(exit). (I remember bug(s) for scope(failure).):


import std.stdio;

void foo() {
  // Bug? Should work for scope(failure) as well.
  scope (exit) {
bar();
  }
  throw new Exception("from foo");
}

void bar() {
  throw new Exception("from bar");
}

void main() {
  try {
foo();

  } catch (Exception exc) {
for (Throwable e = exc; e; e = e.next) {
  writeln(e.msg);
}
  }
}

The output:

from foo
from bar

You can do the same by calling chainTogether(). Here is an excerpt from 
an old experiment of mine:


  try {
foo();

  } catch (Throwable exc) {
Throwable.chainTogether(exc, new Exception(" ... "));
throw exc;
  }

Ali



Re: "min" and "max"

2022-08-09 Thread Ali Çehreli via Digitalmars-d-learn

On 8/9/22 17:03, pascal111 wrote:

> They said " If at least one of the arguments is NaN, the result is an
> unspecified value.

That's called "unorderedness":


http://ddili.org/ders/d.en/floating_point.html#ix_floating_point.unordered

> as a beginner how can I guess what "NaNs"
> means or if it refers to ranges?!

You can use the index: ;)

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

There are a couple of entries for 'nan' there.

Ali



Re: A look inside "filter" function defintion

2022-08-09 Thread Ali Çehreli via Digitalmars-d-learn

On 8/2/22 05:39, pascal111 wrote:

> I'm still stuck. Do you have a
> down-to-earth example for beginners to understand this concept?

I will refer to my explanation because down-to-earth has always been my 
goal. I hope i succeeded:



http://ddili.org/ders/d.en/templates_more.html#ix_templates_more.eponymous%20template

However, my chapters assume that previous chapters have already been read.

Ali



Re: Breaking ";" rule with lambda functions

2022-08-09 Thread Ali Çehreli via Digitalmars-d-learn

On 8/2/22 09:40, pascal111 wrote:

> Maybe I'd wrong beliefs about lambda function. It's already in C++, so
> it's a traditional feature

Lambdas are a common feature of many programming languages. C++ got 
lambdas in their C++11 release, many years after D and many other 
languages had them. (It is not common for the C++ community to give 
credit. Most of their features are presented as C++ inventions when they 
are not. For example, almost the entirety of the C++11 features already 
existed in D (and other languages before D).)


> but the problem is that I didn't use it
> before because I didn't study C++ yet.

C++ is the new-kid-in-the-block when it comes to lambdas.

Getting back to lambda syntax, you don't have to use the shorthand => 
syntax. I try to explain how various syntaxes relate to each other:


  http://ddili.org/ders/d.en/lambda.html#ix_lambda.function,%20lambda

My book is freely available and I think is better than the documentation 
you've shown earlier, which apparently included copies of my text:


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

You can find most of your questions about keywords and syntax in the 
index section:


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

Ali



Re: char* pointers between C and D

2022-08-09 Thread Ali Çehreli via Digitalmars-d-learn

On 7/25/22 06:51, ryuukk_ wrote:
> On Monday, 25 July 2022 at 11:14:56 UTC, pascal111 wrote:

>> const(char)[] ch1 = "Hello World!";
>> char[] ch2="Hello World!".dup;

[...]

> `ch1`is a string literal, just like in C, it is null terminated

To be pedantic, ch1 is not the string literal but a slice of it. "Hello 
world" is the string literal and does have a '\0' at the end.


> `ch2` is a GC allocated char array, it is NOT null terminated

Yes. The only difference between ch1 and ch2 is that ch1 does not incur 
an allocation cost.


Ali



Re: OK to do bit-packing with GC pointers?

2022-08-09 Thread Ali Çehreli via Digitalmars-d-learn

On 7/22/22 09:50, Ben Jones wrote:
> any problems with the GC?

The slides don't seem to mention the GC but Amaury Séchet had given a 
presentation on bit packing:


  http://dconf.org/2016/talks/sechet.html

Ali



Re: "chain" vs "~"

2022-08-08 Thread Ali Çehreli via Digitalmars-d-learn

On 8/6/22 18:22, pascal111 wrote:
> Why we use "chain" while we have "~":
>
> '''D
> int[] x=[1,2,3];
> int[] y=[4,5,6];
>
> auto z=chain(x,y);
> auto j=x~y;
> '''

To add to what has already mentioned,

- chain can be used on ranges that are of different element types

- as usual, some of the ranges may be generators

- although obscure, one may sort in-place over multiple ranges (requires 
RandomAccessRange.)


This program shows the first two points:

import std; // Apologies for terseness

void main() {
  auto ints = [ 10, 3, 7 ];
  auto squares = iota(10).map!squared.take(5);
  auto doubles = [ 1.5, -2.5 ];
  auto c = chain(ints, squares, doubles);

  // Different types but CommonType is 'double' here:
  static assert(is(ElementType!(typeof(c)) == double));

  // Prints [10, 3, 7, 0, 1, 4, 9, 16, 1.5, -2.5]
  writeln(c);
}

auto squared(T)(T value) {
  return value * value;
}

And this one shows how one can sort in-place multiple arrays:

import std; // Ditto

void main() {
  auto a = [ 10, 3, 7 ];
  auto b = [ 15, -25 ];

  auto c = chain(a, b);
  sort(c);

  writeln(a);  // Prints [-25, 3, 7]
  writeln(b);  // Prints [10, 15]
}

Ali



Re: How do I initialize a templated constructor?

2022-08-08 Thread Ali Çehreli via Digitalmars-d-learn

Here is another one that uses nested templates:

import std.stdio;

template TestArray(ulong element_n) {
  struct TestArrayImpl(Type) {
int[element_n] elements;

this(ulong number) {
  pragma(msg, "The type is: ", Type);
  writeln("Constructing with ", number);
}
  }

  auto makeFor(string s)(ulong number) {
return TestArrayImpl!(mixin(s))(number);
  }
}

void main() {
  auto ta = TestArray!10.makeFor!"int"(60);
}

Ali



Re: Acess variable that was set by thread

2022-08-08 Thread Ali Çehreli via Digitalmars-d-learn

On 8/8/22 00:14, vc wrote:

> i will like to hear thoughts even if it works
> for me

__gshared would work as well but I would consider std.concurrency first. 
Just a simple example:


import std.stdio;
import std.concurrency;
import core.thread;

struct Result {
  int value;
}

struct Done {
}

void run()
{
  bool done = false;
  while (!done) {
writeln("Derived thread running.");
receiveTimeout(1.seconds,
(Done msg) {
done = true;
});
  }

  // Send the result to the owner
  // (I made assumptions; the thread may produce
  // results inside the while loop above.)
  ownerTid.send(Result(42));
}

void main()
{
auto worker = spawn();
Thread.sleep(5.seconds);
worker.send(Done());
auto result = receiveOnly!Result();
writeln("Here is the result: ", result);
}

Related, Roy Margalit's DConf 2022 presentation was based on traps 
related to sequential consistency. The video will be moved to a better 
place but the following link should work for now:


  https://youtu.be/04gJXpJ1i8M?t=5658

Ali



Re: How do I initialize a templated constructor?

2022-08-08 Thread Ali Çehreli via Digitalmars-d-learn

On 8/7/22 22:38, rempas wrote:

> I want to create it and be able to successfully initialize the template
> parameters
> of the constructor but until now, I wasn't able to find a way to
> successfully do
> that.

The following method uses a convenience function but it's not really needed:

import std.stdio;

struct TestArray(ulong element_n, string type) {
  int[element_n] elements;
  mixin(type) member;
  pragma(msg, "The type is: ", typeof(member));

  this(ulong number) {
writeln("Constructing with ", number);
  }
}

auto makeTestArray(ulong element_n, string type)(ulong number) {
  return TestArray!(element_n, type)(number);
}

void main() {
  auto ta = makeTestArray!(10, "int")(60);
}

Ali



Re: Ranges

2022-08-07 Thread Ali Çehreli via Digitalmars-d-learn

On 8/6/22 22:58, Salih Dincer wrote:

> Ranges are not like that, all they do is
> generate.

You may be right. I've never seen it that way.

I've been under the following impression:

- C++'s iterators are based on an existing concept: pointers. Pointers 
are iterators.


- D's ranges are based on an existing concept: slices. Slices are ranges.

However, I can't find where I read that.

Ali



Re: Ranges

2022-08-07 Thread Ali Çehreli via Digitalmars-d-learn

On 8/7/22 08:34, pascal111 wrote:

> Everyone knows that slices are not pointers

D's slices are "fat pointers": In D's case, that translates to a pointer 
plus length.


> that pointers are real work,

Agreed. Pointers are fundamental features of CPUs.

> but slices are like a simple un-deep technique that is appropriate for
> beginners,

That is not correct. Slices are designed by a C expert to prevent 
horrible bugs caused by C experts. Most C experts use slices very happily.


> but after that in advanced level in programming, we should
> use pointers to do same tasks we were doing with slices (the easy way of
> beginners).

That is an old thought. Today, we see that no matter how experienced, 
every person needs and appreciates help to prevent bugs. There are many 
cases of bugs killing people, jeopardizing expensive projects, loss of 
personal information, etc.


Ali



Re: Ranges

2022-08-06 Thread Ali Çehreli via Digitalmars-d-learn

On 8/6/22 14:10, pascal111 wrote:

> the problem is that ranges in D lack the usage of pointers as
> an essential tool to make all of ranges functions they need. If ranges
> exist in C, they would use pointers, and this is

There are a few cases where pointers provide functionality that ranges 
cannot:


1) Some algorithms don't make much sense with ranges. For example, most 
of the time find() can return just the element that we seek. In D, 
find() returns a range so that we can chain it with other algorithms.


2) Some algorithms like partition() better use three pointers.

Other than that, ranges are superior to pointers in every aspect. (I 
resent the fact that some C++ "experts" used those two points to decide 
ranges are inferior and helped deprive the C++ community of ranges for a 
very long time. The same "experts" did the same with 'static if'.)


> a powerful point in the account of C.

I missed how you made that connection.

Ali



Re: Ranges

2022-08-06 Thread Ali Çehreli via Digitalmars-d-learn

On 8/6/22 09:33, Salih Dincer wrote:

> the slices feel like ranges, don't they?

Yes because they are ranges. :) (Maybe you meant they don't have range 
member functions, which is true.)


D's slices happen to be the most capable range kind: RandonAccessRange. 
All of the following operations are supported on them as long as one 
imports std.array (or std.range, which publicly does so):


- empty
- front
- popFront
- save
- back
- popBack
- indexed element access

Slices have the optional length property as well (i.e. hasLength).

Those operations are not supported by member functions but by 
free-standing functions.


Ali



Re: Ranges

2022-08-05 Thread Ali Çehreli via Digitalmars-d-learn

On 8/5/22 01:59, frame wrote:
> On Thursday, 4 August 2022 at 22:14:26 UTC, Ali Çehreli wrote:
>
>> No element is copied or moved. :)
>>
>> Ali
>
> I know that :)

And I know that. :) We don't know who else is reading these threads, so 
I didn't want to give wrong impression.


Copying would happen if we added slicing on the left-hand side. However, 
I realized that the following fails with a RangeError:


void main() {
  auto arr = [1, 2, 3];
  arr[0..$-1] = arr[1..$];// <-- Runtime error
}

I suspect the length of the array is stamped too soon. (?)

Should that operation be supported?

Ali



Re: Ranges

2022-08-04 Thread Ali Çehreli via Digitalmars-d-learn

On 8/4/22 11:05, frame wrote:

> `popFront()`

The function was this:

   void popFront() {
  students = students[1 .. $];
   }

> copies all
> elements except the first one into the variable (and overwrites it), so
> it moves the data forward.

That would be very slow. :) What actually happens is, just the two 
variables that define a slice is adjusted.


Slices consist of two members:

struct __an_int_D_array_behind_the_scenes {
  size_t length;
  int * ptr;
}

So,

  students = students[1..$];

is the same as doing the following:

  students.length = (students.length - 1);
  students.ptr = students.ptr + 1;

(ptr's value would change by 4 bytes because 'int'.)

No element is copied or moved. :)

Ali



Re: Ranges

2022-08-04 Thread Ali Çehreli via Digitalmars-d-learn

On 8/4/22 06:08, pascal111 wrote:
> In next code from
> "https://www.tutorialspoint.com/d_programming/d_programming_ranges.htm;,

That page seems to be adapted from this original:

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

> we have two issues:
>
> 1) Why the programmer needs to program "empty()", "front()", and
> "popFront()" functions for ranges

The programmer almost never needs to implement those functions. Existing 
data structures and algorithms are almost always sufficient. (I did need 
to implement them but really rarely.)


I tried to explain what those functions do. I don't like my Students 
example much because wrapping a D slice does not make much sense. Again, 
I just try to explain them.


> while they exist in the language
> library?

The existing front, popFronh, etc. are only for arrays (slices).

> it seems there's no need to exert efforts for that.

Exactly.

> "https://dlang.org/phobos/std_range_primitives.html;
>
> 2) "front()", and "popFront()" are using fixed constants to move forward
> the range, while they should use variables.

Well, 0 is always the first element and 1..$ are always the rest. 
Variables would not add any value there.


However, the example could use the existing library function that you 
mention:


> @property bool empty() const {
>return students.length == 0;

Better:

 import std.array : empty;
 return students.empty;

> }
> @property ref Student front() {
>return students[0];

Better:

 import std.array : front;
 return students.front;

> }
> void popFront() {
>students = students[1 .. $];

Better:

 import std.array : popFront;
 students.popFront();

But I think those implementations might confuse the reader.

Ali



Re: Obsecure problem 2

2022-08-04 Thread Ali Çehreli via Digitalmars-d-learn

On 8/4/22 00:57, pascal111 wrote:

> I don't see my post.

Some posts are blocked by the spam filter. (Apparently, your message did 
not have a sender name and cannot be passed because of that.)


Ali



Re: Converting JSONValue to AssociativeArray.

2022-08-01 Thread Ali Çehreli via Digitalmars-d-learn

On 8/1/22 15:47, Steven Schveighoffer wrote:

You beat me to it. I used .object and .str:

import std;

void main()
{
JSONValue data = parseJSON(`{ "name": "Hype Editor", "hobby": 
"Programming" }`);

writefln("%s", data);

// This already sees the data as an AA but the type is 
JSONValue[string]":

auto o = data.object;
static assert(is(typeof(o) == JSONValue[string]));

writeln("Accessing the data with .str:");
foreach (key, jsonValue; o) {
  writeln("  ", key, ": ", jsonValue.str);
}

// If that much is not sufficient, you can convert it to a
// proper AA like this:
auto aa_data = o
   .byKeyValue
   .map!(kv => tuple(kv.key, kv.value.str))
   .assocArray;
static assert(is(typeof(aa_data) == string[string]));

writeln("Now it's string[string]:");
writefln("  %s", aa_data);
}

Ali



Re: Exclamation symbol "!" within functions syntax

2022-07-27 Thread Ali Çehreli via Digitalmars-d-learn

On 7/27/22 04:00, pascal111 wrote:
I noticed more than once that the exclamation "!" is used within 
functions typing, and it seems like an operator with new use, for 
example "to!int()", ".tee!(l => sum += l.length)", 
"enforce!MissingArguments...", so what dose it means?




The binary ! operator is used for specifying template arguments. I have 
some explanation here:



http://ddili.org/ders/d.en/templates.html#ix_templates.!,%20template%20instance

Ali


Re: Particular exceptions names

2022-07-27 Thread Ali Çehreli via Digitalmars-d-learn

On 7/26/22 16:43, pascal111 wrote:
> In next example code, it used user-made exception,

I am not sure I understand you correctly because the program you show 
throws Exception, which is not user-made at all.


If you want to throw a particual exception that you define, you need to 
inherit that type from Exception.


The following program show an example as well as 'enforce', which I 
prefer over explicit if+throw+else:


import std.stdio;
import std.format;

class MissingArguments : Exception {
  this(string msg, string file = __FILE__, size_t line = __LINE__) {
super(msg, file, line);
  }
}

void main(string[] args) {
  // if (args.length != 42) {
  //   throw new MissingArguments(args.length);
  // }

  import std.exception : enforce;
  enforce!MissingArguments(args.length == 42,
   format!"Too few arguments: %s"(args.length));

  // Program continues here... (No 'else' needed.)
}

Ali



Re: How to create Multi Producer-Single Consumer concurrency

2022-07-13 Thread Ali Çehreli via Digitalmars-d-learn

On 7/13/22 02:25, Bagomot wrote:

> How to do the same with `taskPool` instead of `spawnLinked`?

You are hitting the nail on the head. :) std.parallelism, which taskPool 
is a concept of, is for cases where operations are independent.


However, producer and consumer are by definition dependent, so it's a 
problem for std.concurrency, which involves message boxes.


You can do the same with std.parallelism or core.thread but you would be 
implementing some of what std.concurrency already provides.


The following are my understandings of these topics:

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

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

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

The introduction section of the Concurrency chapter lists some differences.

Ali



Re: Background thread, async and GUI (dlangui)

2022-07-12 Thread Ali Çehreli via Digitalmars-d-learn

On 7/12/22 11:47, Bagomot wrote:

> I now have a couple more questions about `Task`:
> 1) How to run a non-static class method through `task`?
> 2) How to use `taskPool` to run a series of tasks of the same type (from
> question 1)?

As a friendly reminder, these questions could be more useful in a 
separate forum thread. :)


import std.stdio;
import std.parallelism;
import std.algorithm;
import std.range;

interface Animal {
  string song();
}

class Dog : Animal {
  string voice_;

  this(string voice) {
this.voice_ = voice;
  }

  string song() {
return voice_ ~ " " ~ voice_;
  }
}

void main() {
  auto voices = [ "hav", "woof", "bark", "gav", "grrr" ];
  auto dogs = voices.map!(voice => new Dog(voice)).array;

  // No need to specify this; just being silly...
  const workerCount = totalCPUs + 7;

  auto tp = new TaskPool(workerCount);
  scope (exit) tp.finish();

  // a) Classic foreach loop
  foreach (dog; tp.parallel(dogs)) {
writeln(dog.song);
  }

  // b) Adding individual tasks (could be a foreach loop)
  dogs.each!(dog => tp.put(task!(d => writeln(d.song))(dog)));
}

Ali



Re: null == "" is true?

2022-07-12 Thread Ali Çehreli via Digitalmars-d-learn

On 7/12/22 10:11, Steven Schveighoffer wrote:

> The algorithm to compare *any* arrays is first verify the lengths are
> the same. Then for each element in the array, compare them. Since there
> are 0 elements in both the empty string and the null string, they are
> equal.

Checking .empty() covered all of my uses cases. I think... :)

void foo(string s) {
  import std.array;
  assert(s.empty);
}

void main() {
  // Literal null
  foo(null);

  // Zero-length and pointing at '\0'
  foo("");

  // Fresh
  string a;
  foo(a);

  // Shrunk
  string b = "hello";
  b.length = 0;
  assert(b.ptr !is null);
  foo(b);
}

Ali



Re: How can I match every instance of a template type (struct)?

2022-07-12 Thread Ali Çehreli via Digitalmars-d-learn

On 7/12/22 06:34, rempas wrote:

>static if (is(typeof(obj) == Test)) { printf("YES!!!\n"); }

An alternative:

  import std.traits;
  static if (isInstanceOf!(Test, typeof(obj))) { printf("YES!!!\n"); }

https://dlang.org/phobos/std_traits.html#isInstanceOf

Ali



Re: Background thread, async and GUI (dlangui)

2022-07-08 Thread Ali Çehreli via Digitalmars-d-learn

On 7/8/22 06:32, Bagomot wrote:

> I do as in Ali's example, but
> the GUI is still blocked:

I don't know exactly why but something looks suspicious.

> ```d
> auto btn = new Button("Run"d);
> btn.click = delegate(Widget src) {
>  auto request = Request("dlang.org");

That is a local variable which will die after the return statement...

>  auto downloadTask = task!download();

... and that pointer will be invalid, still pointing on function call stack.

At least, I would move the 'auto request' line up, next to 'btn' so that 
it lives long and that you can get the 'result' later on.


But then, you need access to 'task' as well so that you can ensure it 
has finished with downloadTask.yieldForce().


>  downloadTask.executeInNewThread;
>  return true;
> };

Aside: What does the return value 'true' mean?

I am not sure whether my explicit way of starting a thread (albeit with 
std.parallelism) is the right way here. As you've been suspecting, 
dlangui may provide async execution. (?)


Ali



Re: Background thread, async and GUI (dlangui)

2022-07-07 Thread Ali Çehreli via Digitalmars-d-learn

On 7/6/22 16:17, Ali Çehreli wrote:

> I would consider std.parallelism

And it looks more natural with a std.parallelism.Task:

struct Progress {
  size_t percent_;

  void set(size_t downloaded, size_t total) {
if (total != 0) {
  import core.atomic: atomicStore;

  const value = cast(size_t)(float(downloaded) / float(total) * 100);
  atomicStore(percent_, value);
}
  }

  size_t get() const {
import core.atomic: atomicLoad;

return atomicLoad(percent_);
  }
}

struct Request {
  string url;
  string result;
  Progress progress;
}

void download(Request * request) {
  import std.net.curl: HTTP;

  auto http = HTTP(request.url);

  http.onProgress((size_t dl, size_t dln, size_t ul, size_t uln) {
  if (dl != 0) {
request.progress.set(dln, dl);
  }
  return 0;
});

  http.onReceive((ubyte[] data) {
  request.result ~= (cast(char[])data);
  return data.length;
});

  http.perform();
}

void main() {
  import std.parallelism : task;
  import std.stdio: writefln;

  auto request = Request("dlang.org");
  auto downloadTask = task!download();
  downloadTask.executeInNewThread;

  foreach (i; 0 .. 10) {
writefln!"Doing work on the side (%s)"(i);
writefln!"Checking download progress: %s%%"(request.progress.get());

import core.thread;
Thread.sleep(100.msecs);
  }

  // Now we need the result before continuing:
  downloadTask.yieldForce();

  writefln!"Downloaded %s bytes:\n%s"(request.result.length, 
request.result);

}

Ali



Re: Background thread, async and GUI (dlangui)

2022-07-06 Thread Ali Çehreli via Digitalmars-d-learn

On 7/6/22 02:26, Bagomot wrote:

> 1) How to make asynchronous HTTP requests with curl in order to receive
> progress and status? And how do you know that the request is completed?

I don't know how dlangui or others automate this but I had fun writing 
the following program that uses std.concurrency and std.net.curl:


> 3) My application must perform some work in a separate thread (I do this
> through inheritance of the worker from core.thread.Thread, is that
> correct?).

core.thread.Thread is low level. I would consider std.parallelism and 
std.concurrency first. (I use the latter for message passing in the 
program below.)


import std.concurrency;
import std.net.curl;
import std.conv;
import std.stdio;
import std.algorithm;
import std.range;
import std.format;

// Signifies that the main thread requests the getter to stop
// serving. (Not used here.)
struct Done {}

// Represents download progress.
struct Progress {
  size_t downloaded;
  size_t total;
}

// Represents a URL
struct Url {
  string value;
}

// The thread entry point for the getter
void getterFunc() {
  receive(
(Done _) {
  // Not used here but this is for clean termination.
  return;
},

(Url url) {
  // Received a URL to get.
  auto http = HTTP(url.value);

  // std.net.curl.HTTP will call this delegate with progress
  // information...
  http.onProgress((size_t dl, size_t dln, size_t ul, size_t uln) {
if (dl != 0) {
  // ... and we will send it along to the main thread.
  ownerTid.send(Progress(dln, dl));
}
return 0;
  });

  // std.net.curl.HTTP will call this delegate with
  // downloaded parts...
  http.onReceive((ubyte[] data) {
// ... and we will send it along to the main thread.
ownerTid.send((cast(char[])data).to!string);
return data.length;
  });

  // Everything is set up. Let's do it.
  http.perform();
},
  );
}

void main() {
  auto getter = spawnLinked();

  getter.send(Url("dlang.org"));

  string result;
  bool done = false;
  while (!done) {
receive(
  (LinkTerminated msg) {
// (This may or may not be expected.)
stderr.writefln!"The getter thread terminated.";
done = true;
  },

  (Progress progress) {
writeln(progress);
if (!result.empty &&
(progress.downloaded == progress.total)) {
  done = true;
}
  },

  (string part) {
result ~= part;
  },
);
  }

  writefln!"Downloaded %s bytes:\n%s"(result.length, result);
}

Ali



Re: Calling readln() after readf

2022-07-05 Thread Ali Çehreli via Digitalmars-d-learn

On 7/5/22 17:14, Gary Chike wrote:

> So, in order to use `parse!int()`, I would need to separate it into two
> statements with a variable acting as an intermediary:
> ```
> auto input = readln();
> auto age = parse!int(input);

Exactly. parse takes the input by reference (necessitating an lvalue) so 
that the input is consumed for the next step(s) of parsing.


Ali



Re: How to call a function from a dll created with d ?

2022-07-01 Thread Ali Çehreli via Digitalmars-d-learn

On 7/1/22 12:11, Vinod KC wrote:

The following function is dimedll.testFunc:

> ```d
> module dimedll;
// ...
> export void testFunc() {
>  writeln("This is from dll");
> }
> ```

We suspect the name of the file that defines main() is dime.d.

> extern void testFunc();

That symbol belongs to this module, which is implied to be 'module dime'.

>  testFunc();

That's a call to dime.testFunc, which does not exist.

With the provided information alone, the following is what I would do:

1) This dll must have a .di file, which should contain the following:

// dimedll.di
void testFunc();

(.di files can be generated by dmd with its -H command line switch.)

2) Provide dimedll.di as your library's interface file (a la "header file").

3) The users of this dll should import that .di file (declaring the 
functions themselves won't work):


import dimedll;

void main() {
  // ...
}

Ali



Re: Better way to achieve the following

2022-06-21 Thread Ali Çehreli via Digitalmars-d-learn

On 6/21/22 10:09, JG wrote:

Suppose we are often writing something like
```d
theFirstName[theFirstIndex].theSecondName[theSecondIndex].thirdName[theThirdIndex]=x; 


```
One would like to something like
```d
alias shortName = 
theFirstName[theFirstIndex].theSecondName[theSecondIndex].thirdName[theThirdIndex]; 


shortName = x;
```
but you can't alias an expression.


An option is nested functions:

  ref shortName() {
return 
theFirstName[theFirstIndex].theSecondName[theSecondIndex].thirdName[theThirdIndex];

  }

  shortName = x;

Ali


Re: Calling readln() after readf

2022-06-20 Thread Ali Çehreli via Digitalmars-d-learn

On 6/20/22 07:00, Gary Chike wrote:

> Would it be appropriate to forego `readf`
> and read input as a string using `readln` ,benefiting from the `strip`
> function, then convert to their appropriate datatype

Makes sense. The following are related as well:

  https://dlang.org/library/std/conv/parse.html

  https://dlang.org/library/std/format/read/formatted_read.html

Ali



Re: Calling readln() after readf

2022-06-19 Thread Ali Çehreli via Digitalmars-d-learn

On 6/19/22 15:52, Gary Chike wrote:
> On Saturday, 24 April 2021 at 22:13:45 UTC, Ali Çehreli wrote:
>> On 4/24/21 7:46 AM, PinDPlugga wrote:
>> ...
>> As a general solution, you can use a function like this:
>>
>> auto readLine(S = string)(File file = stdin) {
>>   while (!file.eof) {
>> auto line = file.readln!S.strip;
>> if (!line.empty) {
>>   return line;
>> }
>>   }
>>
>>   return null;
>> }
>>
>> Ali
>
> Hi Ali,
>
> Being a new D learner, I've noticed this behavior as well. Thank you for
> providing the 'readLine' function! Would it be considered poor coding
> style to intercept the stream between readf and readln with the
> following statement?  :
>
> ```d
>   auto catcher = readln.strip;
> ```

The original program said "Please enter a number: ". If the program was 
interacting with a human and the human entered a number, then the rest 
of the line would be understood to be ignored and your method works.


On the other hand, the readLine() function would not ignore the rest of 
the line and use it.


But I think yours makes more sense. :)

But when the program interacts with piped data, there may be multiple \n 
characters and all of those might have to be ignored before reading the 
next non-empty line. So you may want to do readln.strip multiple times? 
I don't know. It all depends on the use case.


> P.S. I love your book on D! :)

Thank you! :)

>
> Cheers,
>
> Gary Chike
>

Ali



Re: std.conv.to

2022-06-17 Thread Ali Çehreli via Digitalmars-d-learn

On 6/17/22 10:04, Salih Dincer wrote:

> Isn't foo and bar the same thing?  I don't understand what's the
> difference!

>auto foo = to!Foo("123"); //??

>auto bar = Foo("321");

Yes, they are the same thing.

The OP was looking for a generic way of converting any type to any other 
type as long as there is a way. (Think a function template.) std.conv.to 
can do that because it considers the constructors as well.


Ali



Re: Creating DLL

2022-06-16 Thread Ali Çehreli via Digitalmars-d-learn

On 6/16/22 09:32, Adam D Ruppe wrote:

> This is why an explicit initialization call is the preferred method -
> there, the time it is called is well-defined by the user after initial
> loading is complete.

Agreed but that excludes using the D runtime in 'static this' (and 
shared) blocks, right? If my explicit call to Initialize is in a 'shared 
static this', then I can have only one such block, right?


Ali



Re: Creating DLL

2022-06-16 Thread Ali Çehreli via Digitalmars-d-learn

On 6/16/22 09:07, Sergeant wrote:

> May I ask one more question: why a code like this would work in
> D-application but not in D-DLL?

D programs generated by D compilers automatically initialize the D 
runtime. You can do the same with rt_init:


pragma (crt_constructor)
extern(C) int initialize() { // Can have any name
  return rt_init();
}

And to deinitialize;

pragma (crt_destructor)
extern(C) int terminate() { // Can have any name
  return rt_term();
}

Although, I haven't tested it with a DLL but with .so libraries on 
Linux... :/


This answer may be relevant:

  https://forum.dlang.org/post/t8diks$2l79$1...@digitalmars.com

Ali



Re: map! evaluates twice

2022-06-16 Thread Ali Çehreli via Digitalmars-d-learn

On 6/16/22 00:58, Salih Dincer wrote:

> I guess the developed cached() and cache() are different things,
> right?

cache caches only the front element.

  https://dlang.org/library/std/algorithm/iteration/cache.html

> I tried cached()

cached() is supposed to cache as many elements as needed as long as 
there are ranges that still reference the elements. Technically, 
cached() does not exist because only a couple of people have seen a 
draft of it. :)


Ali



Re: Consuming D libraries from other languages

2022-06-15 Thread Ali Çehreli via Digitalmars-d-learn

On 6/15/22 10:37, Templated Person wrote:
> It there any resources on how to build D static (`.lib` / `.a`) and
> dynamic libraries (`.dll` / `.so`), and then use them from C?
>
> Do I need to link and initialize phobos somehow?

Not Phobos but the D runtime.

> What if I don't want to
> use the D runtime? What happens with module level `this()` and
> `~this()`?

I had difficulty figuring out how everything fit together in a 
complicated scenario. (Different language runtimes calling each other 
and starting the D library.) However the following worked.


> Is there a comprehensive guide on how to do this stuff?

I gave a DConf presentation that answers some of your questions:

  https://dconf.org/2020/online/

Please click the 'November 22' tab on that page to expand "Exposing a D 
Library to Python Through a C API". But here are the links:


Slides: https://dconf.org/2020/online/slides/ali-2.pdf

Video: https://youtu.be/FNL-CPX4EuM

Q: https://youtu.be/M5wtRgfAoAA

Ali


Re: Closures over temporary variables

2022-06-14 Thread Ali Çehreli via Digitalmars-d-learn

On 6/14/22 02:04, bauss wrote:

> You have to do it like this:
>
> ```
> dgs ~= ( (n) => () { writeln(n); })(i);
> ```

The same thing with a named function as well as with iota():

import std.range;
import std.algorithm;
import std.stdio;

void main() {
  void delegate()[] dgs;

  auto makeDg(int i) {
return () => writeln(i);
  }

  foreach (immutable i; 0 .. 3)
  {
dgs ~= makeDg(i);
  }

  iota(3).each!(i => dgs ~= () => writeln(i));

  foreach (dg; dgs)
  {
dg();
  }
}

Ali



Re: a struct as an multidimensional array index

2022-06-11 Thread Ali Çehreli via Digitalmars-d-learn

On 6/11/22 13:36, z wrote:

> i meant with the syntax in (1), the spec's documentation appears to say
> they are equivalent in result with `new *type*[X][Y]` form.
>
> (1) https://dlang.org/spec/expression#new_multidimensional (3. multiple
> argument form)

Thank you. I see now: The values in parentheses are the lengths from the 
outermost to the innermost:


  new int[][][](5, 20, 30)

// The equivalent of int[30][20][5]

Although, I can see how it had to be that way so that when one used less 
number of lengths, the syntax always works from outer to inner in that 
new expression:


  new int[][][](5)

// The equivalent of int[][][5]

Ali



Re: a struct as an multidimensional array index

2022-06-11 Thread Ali Çehreli via Digitalmars-d-learn

On 6/11/22 00:09, z wrote:

> I rechecked and it should be `X Y Z` for static array, but `Z Y X` for
> indexing/dynamic array creating with `new`

How so? I wrote the following program:

import std.stdio;

void main() {
  enum X = 2;
  enum Y = 3;
  enum Z = 4;

  int[X][Y][Z] s;
  int[X][Y][] d = new int[X][Y][Z];

  pragma(msg, typeof(s));
  pragma(msg, typeof(d));
}

It outputs the following for the static and the dynamic arrays:

int[2][3][4]
int[2][3][]

Consistent elements, except the static array has a compile-time known 
length.


Ali



Re: a struct as an multidimensional array index

2022-06-11 Thread Ali Çehreli via Digitalmars-d-learn

On 6/11/22 04:16, Salih Dincer wrote:

> I think D is very consistent with our feelings. That is, the order in
> memory is in the form of rows x columns.

Yet, there are no rows or columns because neither D nor C (nor C++) have 
multip-dimensional arrays. They all have arrays where elements are layed 
out in memory consecutively.


The type of the elements and what they represent is entilery up to the 
programmer.


> But yes, in reverse(column x
> row) when you set it up statically.

If you mean we can set up the memory in any way we want, I agree but 
again, since there are no mult-dimensional arrays, there cannot be the 
reverse of the order.


> This sample code working on pointers
> can be a proof:

If it's prooving that elemets are side-by-side, then it's by spec.

Here is an example where I have array where each element is a column:

import std.stdio;
import std.range;
import std.algorithm;

void main() {
  // I decide that this array represents
  // Three rows of two columns.
  int[][] arr;
  arr.length = 2;
  foreach (ref column; arr) {
column.length = 3;
  }

  setFirstColumn(arr, 1);
  printArray(arr);
}

void setFirstColumn(int[][] arr, int value) {
  // The first element is my first column.
  arr[0][] = value;
}

void printArray(int[][] arr) {
  // Because stdout takes line-by-line,
  // we print a transposition.
  arr.transposed.writefln!"%-(%-(%s %)\n%)";
}

You may think that the final transposition is a trick. No, it was needed 
only because stdout takes line-by-line. If I used a library like 
ncurses, I could have printed my array exactly the way I used it.


The point is, there are no multi-dimensional arrays. Programmers use 
arrays as they need and sometimes the elements are arrays.


Ali



Re: map! evaluates twice

2022-06-10 Thread Ali Çehreli via Digitalmars-d-learn

On 6/10/22 13:47, Steven Schveighoffer wrote:

> `map` calls the lambda for each call to `front`. If you want a cached
> version, use `cache`:

Others don't know but as I will likely show during a lightning talk at 
DConf, I am trying to finish a .cached range algorithm that caches all 
elements that are in use. (It must drop old elements so that an infinite 
range does not require infinite cache.)


It is supposed to evaluate elements only once.

Ali



Re: Run a command-line process with data sent, and retrieve the data.

2022-06-10 Thread Ali Çehreli via Digitalmars-d-learn

On 6/10/22 10:40, Ali Çehreli wrote:

>https://dlang.org/library/std/process/pipe_process.html

I realized you may be happier with the following if all you need is stdout:

  https://dlang.org/library/std/process/execute.html
  https://dlang.org/library/std/process/execute_shell.html

Ali



Re: Run a command-line process with data sent, and retrieve the data.

2022-06-10 Thread Ali Çehreli via Digitalmars-d-learn

On 6/10/22 10:37, Chris Katko wrote:
> I want to pipe in string data to a shell/commandline program, then
> retrieve the output. But the documentation I read appears to only show
> usage for 'Files' for stdin/stdout/stderr.
>
> ala something like this:
> D
> string input = "hello\nworld";
> string output;
> runProcess("grep hello", input, output);
> assert(output = "hello");
> 

  https://dlang.org/library/std/process/pipe_process.html

Ali



Re: Range to Nullable conversion

2022-06-10 Thread Ali Çehreli via Digitalmars-d-learn

On 6/10/22 10:22, Antonio wrote:
> Is there any alternative to ***range front*** that returns a Nullable
> (i.e. **frontAsMonad** or **frontAsNullable**)?

import std;

// Spelling? :)
auto nullablelize(R)(R range) {
  alias E = Nullable!(ElementType!R);

  struct Nullablelize {
enum empty = false;

auto front() {
  if (range.empty) {
return E();

  } else {
return E(range.front);
  }
}

void popFront() {
  if (!range.empty) {
range.popFront();
  }
}

// Other range algorithms like save(), etc. here
  }

  return Nullablelize();
}

void main() {
  // Wow! We can take 10 elements without error. :)
  writeln(iota(5)
  .filter!(i => i % 2)
  .nullablelize
  .take(10));
}

Ali



Re: a struct as an multidimensional array index

2022-06-10 Thread Ali Çehreli via Digitalmars-d-learn

On 6/10/22 08:13, z wrote:

> arrays of arrays has different order for declaration and addressing,
> and declaring array of arrays has different order depending on how you
> declare it and wether it's static or dynamic array, *oof*)
>
> To give you an idea of the situation :
> ```D
>  int[3][1] a;//one array of 3 int
>  writeln(a[0][2]);//first "column", third "row"
> ```

I've written about this multiple times in the past but D's way is 
consistent for me. That must be because I always found C's syntax to be 
very illogical on this. To me, C's problem starts with putting the 
variable name in the middle:


  // C code:
  int a[1][3]; // Why?

So, first, D moves the variable to its consistent place: after the type:

  int i;
  int[N] arr;

Both of those are in the form of "type and then name". Good...

And then, here is the consistency with arrays: "type and then square 
brackets".


  int[] dynamicArray;
  int[N] staticArray;

So, here is where you and I differ:

  int[3][1] arr;  // Ali likes
  int[1][3] arr;  // z wants

I like it because it is consistently "type and then square brackets". 
(It so happens that the type of each element is int[N] in this case.) If 
it were the other way, than array syntax would be inconsistent with 
itself. :) Or, we would have to accept that it is inside-out like in C.


But of course I understand how it is seen as consistent from C's point 
of view. :)


And this is consistent with static vs dynamic as well because again it's 
"type and then square brackets":


  int[1][] a;  // A dynamic array of int[1]
  int[][3] b;  // A static array of 3 int[]s

Ali



Re: a struct as an multidimensional array index

2022-06-10 Thread Ali Çehreli via Digitalmars-d-learn

On 6/10/22 08:01, Ali Çehreli wrote:

> I still don't understand the reason though. The rows would be copied
> without ref but should retain their type as bool[3], a static array. (?)

Ok, now I see the very sinister problem: It is a disaster to combine 
static array lambda parameters with the laziness of range algorithms. 
The following program prints garbage because by the time writeln prints 
the elements, those elements are on invalid places on the stack:


import std;

void main() {
  int[3][3] arr;

  writeln(
arr[]  // Have to slice
.map!(row => row[] // Have to slice
  .map!(element => element))
  );
}

The output is garbage element values.

The programmer must take the parameter of the outer map by reference so 
that the elements are referring to actual elements in 'arr':


.map!((ref row) => /* ... */

I don't think I realized this issue before, which may be caught by 
various combinations of safety compiler switches, which I haven't tried yet.


Ali



'each' can take static arrays

2022-06-10 Thread Ali Çehreli via Digitalmars-d-learn
I know static arrays are not ranges but somehow they work with 'each'. 
With map, I need to slice as 'arr[]':


import std;

void main() {
  int[3] arr;

  arr.each!(e => e);// Compiles
  // arr.map!(e => e);  // Fails to compile
  arr[].map!(e => e);   // Compiles
}

Why the inconsistency?

Ali



Re: a struct as an multidimensional array index

2022-06-10 Thread Ali Çehreli via Digitalmars-d-learn

On 6/10/22 07:38, Ali Çehreli wrote:

> I played with that toString function but for some reason it prints all
> Ts. (?)

Fixed it by changing one of the lambdas to take by reference:

  void toString(scope void delegate(in char[]) sink) const {
import std.algorithm;
sink.formattedWrite!"%-(%-(%s %)\n%)"(
  elements[].map!((ref row) => row[].map!(column => column ? 'T' : 
'f')));

  //   ^^^
  }

I still don't understand the reason though. The rows would be copied 
without ref but should retain their type as bool[3], a static array. (?)


Ali



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