Re: automate tuple creation
On Thursday, 20 January 2022 at 04:38:39 UTC, forkit wrote: all done ;-) // --- module test; import std.stdio : writeln; import std.range : iota, isForwardRange, hasSlicing, hasLength, isInfinite; import std.array : array, Appender; import std.random : Random, unpredictableSeed, dice, choice; import std.algorithm : map, uniq, canFind; @safe: Random rnd; static this() { rnd = Random(unpredictableSeed); } void main() { int recordsNeeded = 2; int boolValuesNeeded = 3; uint[] uniqueIDs; makeUniqueIDs(uniqueIDs, recordsNeeded); uint[][] tuples; createBoolMatrix(tuples, recordsNeeded, boolValuesNeeded); uint[][uint][] records = CreateTupleDictionary(uniqueIDs, tuples); processRecords(records); } auto CreateTupleDictionary(ref uint[] ids, ref uint[][] tuples) { uint[][uint][] records; foreach(i, id; ids) records ~= [ ids[i] : tuples[i] ]; return records.dup; } void processRecords(T)(const ref T t) if (isForwardRange!T && hasSlicing!T && hasLength!T && !isInfinite!T) { t.writeln; // output from above should look like this: // [[999583661:[1, 1, 0]], [999273256:[1, 1, 1]]] // hoping to explore parallel here too... } void createBoolMatrix(ref uint[][] m, size_t numberOfTuples, size_t numberOfBoolsInTuple) { m = iota(numberOfTuples) .map!(i => iota(numberOfBoolsInTuple) .map!(numberOfBoolsInTuple => cast(uint) rnd.dice(0.6, 1.4)) .array).array; } void makeUniqueIDs(ref uint[] arr, size_t sz) { arr.reserve(sz); // id needs to be 9 digits, and needs to start with 999 int[] a = iota(999_000_000, 1_000_000_000).array; // above will contain 1_000_000 records that we can choose from. int i = 0; uint x; while(i != sz) { x = cast(uint)a.choice(rnd); // ensure every id added is unique. if (!arr.canFind(x)) { arr ~= x; i++; } } } // ---
Re: number ranges
Hi, It looks so delicious. 😀 Thank you. On Wednesday, 19 January 2022 at 18:59:10 UTC, Ali Çehreli wrote: And adding length() was easy as well. Finally, I have provided property functions instead of allowing direct access to members. It doesn't matter as we can't use a 3rd parameter. But it doesn't work for any of these types: real, float, double. My solution: ```d size_t length() inout { //return last_ - first_ + 1 - empty_;/* auto len = 1 + last_ - first_; return cast(size_t)len;//*/ } ``` But it only works on integers. In this case, we have two options! The first is to require the use of integers, other 3 parameter usage: ```d // ... size_t length() inout { auto len = 1 + (last - front) / step; return cast(size_t)len; } } unittest { enum { ira = 0.1, irb = 2.09, irc = 0.11 } auto test = inclusiveRange(ira, irb, irc); assert(test.count == 19); auto arr = iota(ira, irb, irc).array; assert(test.length == arr.length); } ``` Salih
Re: automate tuple creation
On Thursday, 20 January 2022 at 04:00:59 UTC, forkit wrote: void makeUniqueIDs(ref uint[] arr, size_t sz) { ... } arrg! what was i thinking! ;-) // --- void makeUniqueIDs(ref uint[] arr, size_t sz) { arr.reserve(sz); // id needs to be 9 digits, and needs to start with 999 int[] a = iota(999_000_000, 1_000_000_000).array; // above will contain 1_000_000 records that we can choose from. int i = 0; uint x; while(i != sz) { x = cast(uint)a.choice(rnd); // ensure every id added is unique. if (!arr.canFind(x)) { arr ~= x; i++; } else i--; } } //--
Re: automate tuple creation
On Thursday, 20 January 2022 at 00:30:44 UTC, H. S. Teoh wrote: Do the id's have to be unique? yep... I'm almost there ;-) // --- module test; import std.stdio : writeln; import std.range : iota, isForwardRange, hasSlicing, hasLength, isInfinite; import std.array : array, Appender; import std.random : Random, unpredictableSeed, dice, choice; import std.algorithm : map, uniq; @safe: Random rnd; static this() { rnd = Random(unpredictableSeed); } void main() { int recordsNeeded = 5; uint[] uniqueIDs; makeUniqueIDs(uniqueIDs, recordsNeeded); writeln(uniqueIDs); uint[][] mArrBool; // e.g: create a matrix consisting of 5 tuples, // with each tuple containing 3 random bools (0 or 1) createBoolMatrix(mArrBool,recordsNeeded, 3); // process just writeln's it's argument at the moment process(mArrBool); // [[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 1, 1], [1, 1, 0]] // to do (integrate a single value taken from uniqueIDs so that each tuple looks like this: [999575454:[1, 1, 1]] // e.g. // processRecords(records); // output from above should look like this below: // [ [999575454:[1, 1, 1]], [999704246:[0, 0, 1]], [69331:[1, 1, 1]], [999678591:[1, 1, 1]], [999691754:[1, 1, 0]] ] } void createBoolMatrix(ref uint[][] m, size_t numberOfTuples, size_t numberOfBoolsInTuple) { m = iota(numberOfTuples) .map!(i => iota(numberOfBoolsInTuple) .map!(numberOfBoolsInTuple => cast(uint) rnd.dice(0.6, 1.4)) .array).array; } void process(T)(const ref T t) if (isForwardRange!T && hasSlicing!T && hasLength!T && !isInfinite!T) { t.writeln; } void processRecords(T)(const ref T t) if (isForwardRange!T && hasSlicing!T && hasLength!T && !isInfinite!T) { t.writeln; } void makeUniqueIDs(ref uint[] arr, size_t sz) { // id needs to be 9 digits, and needs to start with 999 int[] a = iota(999_000_000, 1_000_000_000).array; // can produce a max of 1_000_000 records. Appender!(uint[]) appndr; // pre-allocate space to avoid costly reallocations appndr.reserve(sz+1); foreach(value; 1..(sz + 1)) appndr ~= cast(uint)a.choice(rnd); // just interesting to see often this asserts. //assert(appndr[].array == appndr[].uniq.array); arr = appndr[].uniq.array; // function should not return if this asserts (i.e. app will exit) assert(arr[].array == arr[].uniq.array); } // ---
Re: Using getSymbolsByUDA in a static foreach loop
On Thursday, 20 January 2022 at 01:14:51 UTC, Adam Ruppe wrote: On Thursday, 20 January 2022 at 00:55:33 UTC, Jack Stouffer wrote: static foreach(member; __traits(allMembers, Manager)) member here is a string, not the member. I prefer to call it memberName. Then you __traits(getMember, Manager, memberName) to actually get the alias you can pass to getAttributes. Thanks, that fixed it. Final working version for anyone who finds this thread: ```d import std.traits; import std.stdio; enum Runnable; struct SubSystem { void run() { writeln("SubSystem ran"); } } struct Manager { @Runnable SubSystem subsystem; void run() { static foreach(memberName; __traits(allMembers, Manager)) { static foreach (attribute; __traits(getAttributes, __traits(getMember, Manager, memberName))) { static if (is(attribute == Runnable)) { __traits(getMember, Manager, memberName).run(); } } } } } void main() { Manager m; m.run(); } ```
Re: Using getSymbolsByUDA in a static foreach loop
On Thursday, 20 January 2022 at 00:55:33 UTC, Jack Stouffer wrote: static foreach(member; __traits(allMembers, Manager)) member here is a string, not the member. I prefer to call it memberName. Then you __traits(getMember, Manager, memberName) to actually get the alias you can pass to getAttributes.
Re: Using getSymbolsByUDA in a static foreach loop
On Wednesday, 19 January 2022 at 21:49:12 UTC, Adam D Ruppe wrote: I never use most of std.traits, they just complicate things. Bleh idk, I wouldn't bother with it and loop through the __traits instead. Unless I'm missing something obvious this has to be a DMD bug, because this prints nothing: ```d import std.traits; import std.stdio; enum Runnable; struct SubSystem { void run() { writeln("SubSystem ran"); } } struct Manager { @Runnable SubSystem subsystem; void run() { static foreach(member; __traits(allMembers, Manager)) { static foreach (attribute; __traits(getAttributes, member)) { static if (attribute == Runnable) { __traits(child, Manager, member).run(); } } } } } void main() { Manager m; m.run(); } ``` The `__traits(getAttributes, member)` call always returns an empty tuple. Calling `__traits(getAttributes, Manager.subsystem)` manually works as expected.
Re: automate tuple creation
On Thu, Jan 20, 2022 at 12:12:56AM +, forkit via Digitalmars-d-learn wrote: [...] > createBoolAssociativeMatrix(mArrBool,3, 2); > > [ [1000:[1, 0]], [1001:[1, 1]], [1001:[1, 0]]] > > > where 1000 is some random id... Do the id's have to be unique? If not, std.random.uniform() would do the job. If they have to be unique, you can either use a sequential global counter (a 64-bit counter will suffice -- you'll won't exhaust it for at least 60+ years of bumping the counter once per CPU tick at 8.4 GHz), or use an AA of ids already generated and just call uniform() to generate a new one until it doesn't collide anymore. T -- A mathematician learns more and more about less and less, until he knows everything about nothing; whereas a philospher learns less and less about more and more, until he knows nothing about everything.
Re: automate tuple creation
On Wednesday, 19 January 2022 at 21:59:15 UTC, forkit wrote: so at the moment i can get a set number of tuples, with a set number of bool values contained within each tuple. e.g. createBoolMatrix(mArrBool,3, 2); [[1, 0], [1, 1], [1, 0]] my next challenge (more for myself, but happy for input).. is to enhance this to an return an associative array: e.g createBoolAssociativeMatrix(mArrBool,3, 2); [ [1000:[1, 0]], [1001:[1, 1]], [1001:[1, 0]]] where 1000 is some random id...
Re: why there is a [] at the end of assocArray
On Wednesday, 19 January 2022 at 16:36:36 UTC, Ali Çehreli wrote: On 1/19/22 06:06, michaelbi wrote: On Wednesday, 19 January 2022 at 13:21:32 UTC, Stanislav Blinov wrote: On Wednesday, 19 January 2022 at 13:15:35 UTC, michaelbi wrote: [...] [...] ...because there's an empty line at the end of input.txt? i got it, though i still don't know where the [] come from. i just add strip here: a=>a.idup.strip Works for me on Linux. Perhaps there is an issue with Windows line endings? In any case, the .strip above would not be eliminating empty lines; you need to filter them out e.g. with byLine.filter!(line => !line.empty) Aside: Instead of copying the lines with .idup explicitly, there is .byLineCopy that already does that. Ali I am using windows. Thanks a lot for introducing those funcs. Now I am feeling the D’s quite interesting and powerful :)
Re: how to print "111000" out into 0b111000
On Wednesday, 19 January 2022 at 15:41:31 UTC, Brian Callahan wrote: On Wednesday, 19 January 2022 at 15:01:29 UTC, michaelbi wrote: as captioned... thx. ```d import std.stdio; import std.conv; void main() { writefln("0b%b", to!int("111000", 2)); } ``` Got it, thanks
Re: automate tuple creation
On 1/19/22 15:21, H. S. Teoh wrote: > On Wed, Jan 19, 2022 at 02:33:02PM -0800, Ali Çehreli via Digitalmars-d-learn wrote: > [...] >> // Returning a dynamically allocated array looks expensive >> // here. Why not use a struct or std.typecons.Tuple instead? > > Premature optimization. ;-) Not in this case because I am pointing at premature pessimization. :) There is no reason to use two-element dynamic arrays when uint[2], Tuple!(uint, uint), and structs are available. > There's nothing wrong with allocating an > array. Agreed. Ali
Re: automate tuple creation
On Wednesday, 19 January 2022 at 22:35:58 UTC, Ali Çehreli wrote: so I combined ideas from all responses: // -- module test; import std.stdio : writeln; import std.range : iota, isForwardRange, hasSlicing, hasLength, isInfinite, array; import std.random : Random, unpredictableSeed, dice; import std.algorithm : map; @safe: Random rnd; static this() { rnd = Random(unpredictableSeed); } void main() { uint[][] mArrBool; // e.g: create a matrix consisting of 5 tuples, with each tuple containing 3 random bools (0 or 1) createBoolMatrix(mArrBool,5, 2); process(mArrBool); } void createBoolMatrix(ref uint[][] m, size_t numberOfTuples, size_t numberOfBoolsInTuple) { m = iota(numberOfTuples) .map!(i => iota(numberOfBoolsInTuple) .map!(numberOfBoolsInTuple => cast(uint) rnd.dice(0.6, 1.4)) .array).array; } void process(T)(const ref T t) if (isForwardRange!T && hasSlicing!T && hasLength!T && !isInfinite!T) { t.writeln; } //--
Re: automate tuple creation
On Wednesday, 19 January 2022 at 23:22:17 UTC, forkit wrote: oops // e.g: create a matrix consisting of 5 tuples, with each tuple containing 3 random bools (0 or 1) createBoolMatrix(mArrBool,5, 3);
Re: automate tuple creation
On Wed, Jan 19, 2022 at 02:33:02PM -0800, Ali Çehreli via Digitalmars-d-learn wrote: [...] > // Returning a dynamically allocated array looks expensive > // here. Why not use a struct or std.typecons.Tuple instead? Premature optimization. ;-) There's nothing wrong with allocating an array. If you're worried about memory efficiency, you could allocate the entire matrix in a single block and just assemble slices of it in the outer block, like this: uint[][] createBoolMatrix(size_t count) { auto buffer = new uint[count*count]; return iota(count).map!(i => buffer[count*i .. count*(i+1)]) .array; } This lets you do only 2 GC allocations instead of (1+count) GC allocations. May help with memory fragmentation if `count` is large and you create a lot of these things. But I honestly wouldn't bother with this unless your memory profiler is reporting a problem in this aspect of your program. It just adds complexity to your code (== poorer long-term maintainability) for meager benefits. T -- What do you call optometrist jokes? Vitreous humor.
Re: automate tuple creation
On 1/19/22 14:33, Ali Çehreli wrote: > Random rnd; > > shared static this() { >rnd = Random(unpredictableSeed); > } But that's a mistake: If rnd is thread-local like that, it should be initialized in a 'static this' (not 'shared static this'). Otherwise, only the main thread's 'rnd' would be randomized, which is the only thread that executes 'shared static this' blocks. Ali
Re: automate tuple creation
On 1/19/22 13:59, forkit wrote: > void createBoolMatrix(ref uint[][] m) > { > auto rnd = Random(unpredictableSeed); That works but would be unnecessarily slow and be against the idea of random number generators. The usual approach is, once you have a randomized sequence, you just continue using it. For example, I move rnd to module scope and initialize it once. Random rnd; shared static this() { rnd = Random(unpredictableSeed); } auto randomValue() { return cast(uint)rnd.dice(0.6, 1.4); } // Returning a dynamically allocated array looks expensive // here. Why not use a struct or std.typecons.Tuple instead? auto randomTuple() { return [ randomValue(), randomValue() ]; } void createBoolMatrix(ref uint[][] m, size_t count) { import std.algorithm : map; import std.range : iota; m = count.iota.map!(i => randomTuple()).array; } Ali
Re: automate tuple creation
On Wed, Jan 19, 2022 at 09:59:15PM +, forkit via Digitalmars-d-learn wrote: > so I have this code below, that creates an array of tuples. > > but instead of hardcoding 5 tuples (or hardcoding any amount of > tuples), what I really want to do is automate the creation of > how-ever-many tuples I ask for: > > i.e. > > instead of calling this: createBoolMatrix(mArrBool); > I would call something like this: createBoolMatrix(mArrBool,5); // > create an array of 5 typles. Why can't you just use a loop to initialize it? uint[][] createBoolMatrix(size_t n) { auto result = new uint[][n]; // allocate outer array foreach (ref row; result) { row = new uint[n]; // allocate inner array foreach (ref cell; row) { cell = cast(uint) rnd.dice(0.6, 1.4); } } return result; } Or, if you wanna use those new-fangled range-based idioms: uint[][] createBoolMatrix(size_t n) { return iota(n) .map!(i => iota(n) .map!(j => cast(uint) rnd.dice(0.6, 1.4)) .array) .array; } T -- Verbing weirds language. -- Calvin (& Hobbes)
Re: automate tuple creation
On Wednesday, 19 January 2022 at 21:59:15 UTC, forkit wrote: oh. that randomShuffle was unnecessary ;-)
automate tuple creation
so I have this code below, that creates an array of tuples. but instead of hardcoding 5 tuples (or hardcoding any amount of tuples), what I really want to do is automate the creation of how-ever-many tuples I ask for: i.e. instead of calling this: createBoolMatrix(mArrBool); I would call something like this: createBoolMatrix(mArrBool,5); // create an array of 5 typles. Some ideas about direction would be welcome ;-) // --- module test; import std.stdio; import std.range; import std.traits; import std.random; @safe: void main() { uint[][] mArrBool; createBoolMatrix(mArrBool); process(mArrBool); } void process(T)(const ref T t) if (isForwardRange!T && !isInfinite!T) { t.writeln; // sample output -> [[0, 1], [1, 0], [1, 1], [1, 1], [1, 1]] } void createBoolMatrix(ref uint[][] m) { auto rnd = Random(unpredictableSeed); // btw. below does register with -profile=gc m = [ [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd), [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd), [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd), [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd), [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd) ]; } // --
Re: Using getSymbolsByUDA in a static foreach loop
On Wednesday, 19 January 2022 at 21:44:57 UTC, Jack Stouffer wrote: The error is actually coming from trying to use the result of getSymbolsByUDA in the right part of the `static foreach` huh.. I never use most of std.traits, they just complicate things. Bleh idk, I wouldn't bother with it and loop through the __traits instead.
Re: Using getSymbolsByUDA in a static foreach loop
On Wednesday, 19 January 2022 at 20:53:29 UTC, Adam D Ruppe wrote: So you want to `__traits(child, system, this).run()` and it should work - the traits child will re-attach a this value. The error is actually coming from trying to use the result of getSymbolsByUDA in the right part of the `static foreach`, not the call to the `run` function. Which was odd to me because I thought it just returned a `AliasSeq`. Here's a link to the erroring code with your traits change: https://run.dlang.io/is/gO84ox
Re: Using getSymbolsByUDA in a static foreach loop
On Wednesday, 19 January 2022 at 20:46:17 UTC, Jack Stouffer wrote: static foreach(system; getSymbolsByUDA!(Manager, Runnable)) { system.run(); onlineapp.d(16): Error: value of `this` is not known at compile time The getSymbols returns aliases, meaning you hit what I wrote about a few days ago: http://dpldocs.info/this-week-in-d/Blog.Posted_2022_01_10.html#tip-of-the-week The `this` is a runtime value and all the other `static` things work on compile time info. So you want to `__traits(child, system, this).run()` and it should work - the traits child will re-attach a this value.
Using getSymbolsByUDA in a static foreach loop
I'm trying to use getSymbolsByUDA in order to loop over all of the members in a struct with a certain UDA, and then call a function on the member. The plan is to use this to avoid looping over an array of function pointers. However, the compiler is giving a strange error and the documentation of getSymbolsByUDA is unhelpful, as there are no practical use-case examples. Here's a very simplified version of my code ```d import std.traits; enum Runnable; struct SubSystem { void run(); } struct Manager { @Runnable SubSystem subsystem; void run() { static foreach(system; getSymbolsByUDA!(Manager, Runnable)) { system.run(); } } } void main() { Manager m; m.run(); } ``` Result: ``` onlineapp.d(16): Error: value of `this` is not known at compile time ``` This seems to me to be the logical way to write this code. What am I missing?
Re: number ranges
On 1/19/22 04:51, Salih Dincer wrote: > Is it okay to swap places instead of throwing an error? I would be happier if my potential mistake is caught instead of the library doing something on its own. > Let's also > implement BidirectionalRange, if okay. I had started experimenting with that as well. The implementation below does not care if popFront() or popBack() are called on empty ranges. The programmer must be careful. :) > "Does it reverse the result > in case ```a > b``` like we > did with foreach_reverse()" No, it should not reverse the direction that way because we already have retro. :) inclusiveRange(1, 10).retro; Improving the range as a BidirectionalRange requires three more functions: save(), back(), and popBack(). I am also removing the silly 'const' qualifiers from member functions because a range object is supposed to be mutated. I came to that conclusion after realizing that save() cannot be 'const' because it break isForwardRange (which is required by isBidirectionalRange). Ok, I will change all 'const's to 'inout's in case someone passes an object to a function that takes by 'const' and just applies e.g. empty() on it. And adding length() was easy as well. Finally, I have provided property functions instead of allowing direct access to members. struct InclusiveRange(T) { import std.format : format; T first_; T last_; bool empty_; this(U)(in U first, in U last) in (first <= last, format!"Invalid range: [%s,%s]."(first, last)) { this.first_ = first; this.last_ = last; this.empty_ = false; } T front() inout { return first_; } bool empty() inout { return empty_; } void popFront() { if (first_ == last_) { empty_ = true; } else { ++first_; } } auto save() inout { return this; } T back() inout { return last_; } void popBack() { if (first_ == last_) { empty_ = true; } else { --last_; } } size_t length() inout { return last_ - first_ + 1 - empty_; } } auto inclusiveRange(T)(in T first, in T last) { return InclusiveRange!T(first, last); } unittest { // Invalid range should throw import std.exception : assertThrown; assertThrown!Error(inclusiveRange(2, 1)); } unittest { // Should not be possible to have an empty range import std.algorithm : equal; auto r = inclusiveRange(42, 42); assert(!r.empty); assert(r.equal([42])); } unittest { // Should be able to represent all values of a type import std.range : ElementType; import std.algorithm : sum; auto r = inclusiveRange(ubyte.min, ubyte.max); static assert(is(ElementType!(typeof(r)) == ubyte)); assert(r.sum == (ubyte.max * (ubyte.max + 1)) / 2); } unittest { // Should produce the last value import std.algorithm : sum; assert(inclusiveRange(1, 10).sum == 55); } unittest { // Should work with negative values import std.algorithm : equal; assert(inclusiveRange(-3, 3).equal([-3, -2, -1, 0, 1, 2, 3])); assert(inclusiveRange(-30, -27).equal([-30, -29, -28, -27])); } unittest { // length should be correct import std.range : enumerate, iota; enum first = 5; enum last = 42; auto r = inclusiveRange(first, last); // Trusting iota's implementation size_t expectedLength = iota(first, last).length + 1; size_t i = 0; do { assert(r.length == expectedLength); r.popFront(); --expectedLength; } while (!r.empty); } unittest { // Should provide the BidirectionalRange interface import std.range : retro; import std.algorithm : equal; auto r = inclusiveRange(1, 10); assert(!r.save.retro.equal(r.save)); assert(r.save.retro.retro.equal(r.save)); } void main() { import std.stdio; import std.range; writeln(inclusiveRange(1, 10)); writeln(inclusiveRange(1, 10).retro); auto r = inclusiveRange(1, 11); while (true) { writefln!"%s .. %s length: %s"(r.front, r.back, r.length); r.popFront(); if (r.empty) { break; } r.popBack(); if (r.empty) { break; } } } Ali
Re: why there is a [] at the end of assocArray
On 1/19/22 06:06, michaelbi wrote: On Wednesday, 19 January 2022 at 13:21:32 UTC, Stanislav Blinov wrote: On Wednesday, 19 January 2022 at 13:15:35 UTC, michaelbi wrote: Â Â Â foreach(line; > File("input.txt").byLine.map!(a=>a.idup).array.transposed) so why there is a [] at the end of assocArray printed? thanks. ...because there's an empty line at the end of input.txt? i got it, though i still don't know where the [] come from. i just add strip here: a=>a.idup.strip Works for me on Linux. Perhaps there is an issue with Windows line endings? In any case, the .strip above would not be eliminating empty lines; you need to filter them out e.g. with byLine.filter!(line => !line.empty) Aside: Instead of copying the lines with .idup explicitly, there is .byLineCopy that already does that. Ali
Re: how to print "111000" out into 0b111000
On Wednesday, 19 January 2022 at 15:01:29 UTC, michaelbi wrote: as captioned... thx. ```d import std.stdio; import std.conv; void main() { writefln("0b%b", to!int("111000", 2)); } ```
Re: Function prototype overloading does not work ?
On 1/19/22 3:47 AM, Enjoys Math wrote: ``` module expr; import dots; import operator; import equation; import var; import var_expr; import zz_const; class Expr { public:   void opBinary(string op)(string s) const   {  static if (op == "+")  { Expr right = null; if (s == ".." || s == "..." || s == "") {    right = new Dots(); } if (right !is null)    return new Op("+", [this, right]);  }   }   override string toString() const   {  assert(0);   }   Expr sub(Expr x, Expr y)   {  if (this == x) return y;  return this;   }   Expr sub(Expr x, ref Var y)   {  return sub(x, new VarExpr(y));   }   Expr sub(ref Var x, Expr y)   {  return sub(new VarExpr(x), y);   }   Expr sub(int x, Expr y)   {  return sub(ZZ(x), y);   }   Expr sub(Expr x, int y)   {  return sub(x, ZZ(y));   }   Expr sub(ref Var x, ref Var y)   {  return sub(new VarExpr(x), new VarExpr(y));   }   Expr sub(ref Var x, int y)   {  return sub(new VarExpr(x), ZZ(y));   }   Expr sub(int x, ref Var y)   {  return sub(ZZ(x), new VarExpr(y));   }   override bool opEquals(Object o) {  return this is o;   } } ``` See all the overloads I had to make to sub in order to bypass identity assignment for classes. I.e. Var can't be of type Expr.  Anyway, this approach is not working because code calling `Expr.sub(int, Var)` is not seeing the definitions. It says no function matching those args, but clearly there are! sub(int, ref Var) exists, but not sub(int, Var). Is your Var an lvalue? Without more code context, this is hard to diagnose. Can you post the offending call? -Steve
how to print "111000" out into 0b111000
as captioned... thx.
Re: why there is a [] at the end of assocArray
On Wednesday, 19 January 2022 at 14:06:45 UTC, michaelbi wrote: i got it, though i still don't know where the [] come from. $ rdmd --eval 'writeln("".array.strip.sort.group.assocArray)' [] $ rdmd --eval 'writeln(typeid("".array.strip.sort.group.assocArray))' uint[dchar] It's what an empty AA looks like.
Re: why there is a [] at the end of assocArray
On Wednesday, 19 January 2022 at 13:21:32 UTC, Stanislav Blinov wrote: On Wednesday, 19 January 2022 at 13:15:35 UTC, michaelbi wrote: foreach(line; > File("input.txt").byLine.map!(a=>a.idup).array.transposed) so why there is a [] at the end of assocArray printed? thanks. ...because there's an empty line at the end of input.txt? i got it, though i still don't know where the [] come from. i just add strip here: a=>a.idup.strip
Re: why there is a [] at the end of assocArray
On Wednesday, 19 January 2022 at 13:15:35 UTC, michaelbi wrote: foreach(line; > File("input.txt").byLine.map!(a=>a.idup).array.transposed) so why there is a [] at the end of assocArray printed? thanks. ...because there's an empty line at the end of input.txt?
why there is a [] at the end of assocArray
input: 00100 0 10110 10111 10101 0 00111 11100 1 11001 00010 01010 code: void main() { foreach(line; File("input.txt").byLine.map!(a=>a.idup).array.transposed){ auto sortgroup = line.array.strip.sort.group.assocArray; writeln(sortgroup); } } output: ['1':7, '0':5] ['1':5, '0':7] ['1':8, '0':4] ['1':7, '0':5] ['1':5, '0':7] [] so why there is a [] at the end of assocArray printed? thanks.
Re: number ranges
On Tuesday, 18 January 2022 at 23:13:14 UTC, Ali Çehreli wrote: But I like the following one better because it is fast and I think it works correctly. Is it okay to swap places instead of throwing an error? Let's also implement BidirectionalRange, if okay. This great struct will now run 4x4 like a Jeep. 😀 Moreover, the iota doesn't even care if define char type. And no throwing an error. The real question to ask is: "Does it reverse the result in case ```a > b``` like we did with foreach_reverse()" Salih ```d import std; struct InclusiveRange(T) { T front, last; this(U)(in U front, in U last) { this.front = front; this.last = last; if(empty) toogleFrontLast(); } bool empty() { return front > last; } void popFront() { if(!empty) ++front; } T back() { return last; } void popBack() { if(!empty) --last; } void toogleFrontLast() { auto temp = this.last; this.last = this.front; this.front = temp; } } auto inclusiveRange(T)(T first, T last) { return InclusiveRange!T(first, last); } enum a = 8; // ASCII 80: P enum b = 7; // ASCII 70: F alias type = char; alias test = inclusiveRange; void main() { string str; // for tests... auto io = iota!type(a * 10, b * 10); io.writeln("\n", typeof(io).stringof, "\n"); str = to!string(io); assert(str == "[]"); // OMG, why? auto ir = test!type(a * 10, b * 10); ir.writeln("\n", typeof(ir).stringof, "\n"); str = to!string(ir); assert(str == "FGHIJKLMNOP"); // Ok foreach_reverse(c; ir) str ~= c; assert(str == "FGHIJKLMNOPPONMLKJIHGF"); // Ok } ```
Re: Improve a simple event handler
On Sunday, 16 January 2022 at 20:01:09 UTC, JN wrote: On Saturday, 15 January 2022 at 23:15:16 UTC, JN wrote: Is there some way I could improve this with some D features? My main gripes with it are: Managed to dramatically simplify it to 10 lines of code with variadic templates. ```d import std.stdio; struct Event(T...) { void function(T)[] listeners; void addListener(void function(T) handler) { listeners ~= handler; } void emit(T args) { foreach (listener; listeners) { listener(args); } } } void onResize(uint newWidth, uint newHeight) { writefln("Resized: %d %d", newWidth, newHeight); } void main() { Event!(uint, uint) windowResizeEvent; windowResizeEvent.addListener(&onResize); windowResizeEvent.emit(1000, 2000); } ``` I am very happy with this solution. My advice is to make your listeners return a boolean. This boolean is used to basically stop propagating the event. And debugging it seems really hard to be honest, so, incrementing it a little, I would do: ```d struct ListenerInfo { string name; string file; uint line; string registeredAt; } struct Event(T...) { bool function(T)[] listeners; ListenerInfo[] info; void addListener(bool function(T) handler, string name, string file = __FILE__, uint line = __LINE__, string registeredAt = __PRETTY_FUNCTION__) { listeners~= handler; info~= ListenerInfo(name, file, line, registeredAt); } void emit(T args) { foreach(i, l; listeners) { if(l(args)) { writeln(info[i]); break; } } } } ``` You could even extend this concept further by making it return an enum value for actually removing the listener when executed, stopping propagation. Or you could have access to the listener info inside the arguments too.
Re: Debug symbols from libs not being linked on windows
On Wednesday, 19 January 2022 at 02:31:31 UTC, Hipreme wrote: I have separated my project in a bunch of modules to be compiled separated. But it seems I have lost my debugging power since then. I would like to know if there is any workaround beside not using it as a lib. I'm using it from dub and it is has the debug options on them: ``` "buildOptions": [ "debugMode", "debugInfo", "debugInfoC" ], ``` And on every lib too. I had some errors about "duplicate object file, linking without debug info", an error that really should not exist as D works in modules. But I have renamed the necessary modules for getting rid of that message. After that, the problem was fixed by doing `dub clean --all-packages`, thanks rikki!
Re: Throw stack trace from program kill
On Sunday, 16 January 2022 at 18:03:53 UTC, Paul Backus wrote: On Sunday, 16 January 2022 at 15:15:07 UTC, Hipreme wrote: Is there some way to throw a stack trace when killing the program from the CTRL+C from the terminal? It would help a lot into debugging occasional infinity loops On POSIX, you can use the `sigaction` function to install a signal handler for `SIGINT`, the signal generated by CTRL+C. To terminate the program with a stack trace, simply have the signal handler `throw` an `Error`. Here's an example program that demonstrates the technique: ```d import core.sys.posix.signal; extern(C) void handleCtrlC(int) { throw new Error("Killed by CTRL+C"); } void main() { sigaction_t act = { sa_handler: &handleCtrlC }; int errcode = sigaction(SIGINT, &act, null); f(); // call some functions } void f() { g(); } void g() { h(); } void h() { while (1) {} // wait for ctrl+c } ``` Make sure to compile with the `-g` option if you want your stack trace to have filenames and line numbers. ```d import std.stdio; version(Posix) { import core.sys.posix.signal; extern(C) void handleCtrlC(int) { throw new Error("Killed by CTRL+C"); } bool setupSignal() { sigaction_t act = {sa_handler: &handleCtrlC}; int errCode = sigaction(SIGINT, &act, null); return errCode == 0; } } else version(Windows) { import core.sys.windows.windef; import core.sys.windows.wincon; extern(Windows) BOOL handleCtrlC(DWORD dwType) { switch(dwType) { case CTRL_C_EVENT: throw new Error("Killed by CTRL+C"); break; case CTRL_BREAK_EVENT: throw new Error("Killed by break"); break; default: throw new Error("Killed by unknown event"); break; } return TRUE; } bool setupSignal() { return SetConsoleCtrlHandler(cast(PHANDLER_ROUTINE)&handleCtrlC, TRUE) == TRUE; } } else{bool setupSignal(){return false;}} void a(){b();} void b(){c();} void c(){for(;;){}} void main(string[] args) { if(!setupSignal) writeln("Could not setup signal, exiting."); else a(); } ``` This is my current solution. The problem is that on Windows, it actually has the stack trace: ``` 0x76909A63 in CtrlRoutine 0x76BD6359 in BaseThreadInitThunk 0x76FF7B74 in RtlGetAppContainerNamedObjectPath 0x76FF7B44 in RtlGetAppContainerNamedObjectPath ``` If I throw that error on the Ctrl, it actually shows a message box: `The exception unknown software exception (0xe0441) occurred in the application at location: ...` Maybe there is some specific formatting for throwing exceptions to Windows recognize it?
Re: Function prototype overloading does not work ?
On Wednesday, 19 January 2022 at 08:47:27 UTC, Enjoys Math wrote: ``` module expr; import dots; import operator; import equation; import var; import var_expr; import zz_const; class Expr { public: void opBinary(string op)(string s) const { static if (op == "+") { Expr right = null; if (s == ".." || s == "..." || s == "") { right = new Dots(); } if (right !is null) return new Op("+", [this, right]); } } override string toString() const { assert(0); } Expr sub(Expr x, Expr y) { if (this == x) return y; return this; } Expr sub(Expr x, ref Var y) { return sub(x, new VarExpr(y)); } Expr sub(ref Var x, Expr y) { return sub(new VarExpr(x), y); } Expr sub(int x, Expr y) { return sub(ZZ(x), y); } Expr sub(Expr x, int y) { return sub(x, ZZ(y)); } Expr sub(ref Var x, ref Var y) { return sub(new VarExpr(x), new VarExpr(y)); } Expr sub(ref Var x, int y) { return sub(new VarExpr(x), ZZ(y)); } Expr sub(int x, ref Var y) { return sub(ZZ(x), new VarExpr(y)); } override bool opEquals(Object o) { return this is o; } } ``` See all the overloads I had to make to sub in order to bypass identity assignment for classes. I.e. Var can't be of type Expr. Anyway, this approach is not working because code calling `Expr.sub(int, Var)` is not seeing the definitions. It says no function matching those args, but clearly there are! Try replacing methods sub with template: ```d module expr; import dots; import operator; import equation; import var; import var_expr; import zz_const; class Expr { public: void opBinary(string op)(string s) const; override string toString() const; Expr sub(Expr x, Expr y) { if (this == x) return y; return this; } //template sub: Expr sub(T, U)(auto ref T x, auto ref U y){ //transform parameter to Expr: static Expr expr(E)(auto ref E e){ static if(is(E : Expr)) return e; else static if(is(E : int)) return ZZ(e); else static if(is(E : Var)) return new VarExpr(e); else static assert(0, "no impl " ~ E.stringof); } //call sub(Expr, Expr) this.sub(expr(x), expr(y)); } override bool opEquals(Object o) ; } ```
Re: Function prototype overloading does not work ?
On Wednesday, 19 January 2022 at 08:47:27 UTC, Enjoys Math wrote: ``` module expr; import dots; import operator; import equation; import var; import var_expr; import zz_const; class Expr { public: void opBinary(string op)(string s) const { static if (op == "+") { Expr right = null; if (s == ".." || s == "..." || s == "") { right = new Dots(); } if (right !is null) return new Op("+", [this, right]); } } override string toString() const { assert(0); } Expr sub(Expr x, Expr y) { if (this == x) return y; return this; } Expr sub(Expr x, ref Var y) { return sub(x, new VarExpr(y)); } Expr sub(ref Var x, Expr y) { return sub(new VarExpr(x), y); } Expr sub(int x, Expr y) { return sub(ZZ(x), y); } Expr sub(Expr x, int y) { return sub(x, ZZ(y)); } Expr sub(ref Var x, ref Var y) { return sub(new VarExpr(x), new VarExpr(y)); } Expr sub(ref Var x, int y) { return sub(new VarExpr(x), ZZ(y)); } Expr sub(int x, ref Var y) { return sub(ZZ(x), new VarExpr(y)); } override bool opEquals(Object o) { return this is o; } } ``` See all the overloads I had to make to sub in order to bypass identity assignment for classes. I.e. Var can't be of type Expr. Anyway, this approach is not working because code calling `Expr.sub(int, Var)` is not seeing the definitions. It says no function matching those args, but clearly there are! Firstly, in my opinion, you should be using `auto ref` which will do the same thing as generating by reference and by value declarations. Or you could even use `in` as the compiler will optimize the call for passing it by reference. Now, you could have some self contained example for we being able to test it
Function prototype overloading does not work ?
``` module expr; import dots; import operator; import equation; import var; import var_expr; import zz_const; class Expr { public: void opBinary(string op)(string s) const { static if (op == "+") { Expr right = null; if (s == ".." || s == "..." || s == "") { right = new Dots(); } if (right !is null) return new Op("+", [this, right]); } } override string toString() const { assert(0); } Expr sub(Expr x, Expr y) { if (this == x) return y; return this; } Expr sub(Expr x, ref Var y) { return sub(x, new VarExpr(y)); } Expr sub(ref Var x, Expr y) { return sub(new VarExpr(x), y); } Expr sub(int x, Expr y) { return sub(ZZ(x), y); } Expr sub(Expr x, int y) { return sub(x, ZZ(y)); } Expr sub(ref Var x, ref Var y) { return sub(new VarExpr(x), new VarExpr(y)); } Expr sub(ref Var x, int y) { return sub(new VarExpr(x), ZZ(y)); } Expr sub(int x, ref Var y) { return sub(ZZ(x), new VarExpr(y)); } override bool opEquals(Object o) { return this is o; } } ``` See all the overloads I had to make to sub in order to bypass identity assignment for classes. I.e. Var can't be of type Expr. Anyway, this approach is not working because code calling `Expr.sub(int, Var)` is not seeing the definitions. It says no function matching those args, but clearly there are!