Re: Recommendations on avoiding range pipeline type hell
Thanks to everyone who has replied. You've given me a lot to think about, and since I'm not yet fluent in D it will take a bit to digest it all, though one thing is clear. This community is one of the strong features of D. I will mention it to others as a selling point. Best,
Re: Filter for opDispatch?
On Sunday, 16 May 2021 at 04:38:52 UTC, Mike Parker wrote: On Sunday, 16 May 2021 at 04:07:15 UTC, frame wrote: But the same with fields work? They are also protected. I'm not sure what you mean by "fields" here. ```d protected: // inaccessible /* void s(int v) { _s = v; } int s() { return _s; }*/ // no problem here? int s; ```
Re: Filter for opDispatch?
On Sunday, 16 May 2021 at 04:07:15 UTC, frame wrote: But the same with fields work? They are also protected. I'm not sure what you mean by "fields" here.
Re: Filter for opDispatch?
On Sunday, 16 May 2021 at 03:19:04 UTC, Mike Parker wrote: On Sunday, 16 May 2021 at 00:04:39 UTC, frame wrote: Yes, but why should the derived class not have access to it? I don't think that's your problem. From the template docs: _TemplateInstances_ are always instantiated in the scope of where the _TemplateDeclaration_ is declared... Your `opDispatch` templates are instantiated in the scope of `Base`, from which `_s` is not accessible when it's protected. Indeed, the error goes away if each derived class has its own implementation. But the same with fields work? They are also protected.
Re: Filter for opDispatch?
On Sunday, 16 May 2021 at 00:04:39 UTC, frame wrote: Yes, but why should the derived class not have access to it? I don't think that's your problem. From the template docs: _TemplateInstances_ are always instantiated in the scope of where the _TemplateDeclaration_ is declared... Your `opDispatch` templates are instantiated in the scope of `Base`, from which `_s` is not accessible when it's protected.
Re: Filter for opDispatch?
On Sunday, 16 May 2021 at 00:04:39 UTC, frame wrote: On Saturday, 15 May 2021 at 23:59:49 UTC, Paul Backus wrote: Does it work if you remove `protected` from the derived class? Yes, but why should the derived class not have access to it? Possibly because you're accessing it from an `opDispatch` method defined in the base class. I'm not 100% sure how `protected` works in that case, but just from reading the spec it seems like it could be an issue.
Re: ugly and/or useless features in the language.
I want to be able to support CP936, not just UTF8. I can't use CP936. It's my pet peeve. Hopefully we can solve the coding problem just like Python with #encoding= GBK.
Re: Filter for opDispatch?
On Saturday, 15 May 2021 at 23:59:49 UTC, Paul Backus wrote: On Saturday, 15 May 2021 at 23:41:19 UTC, frame wrote: On Friday, 14 May 2021 at 23:02:22 UTC, frame wrote: Thanks! I stumbled around with static asserts and mixins... totally forgot about the constraints but they will to the trick. Now I run into the error "class Foo member s is not accessible" "template instance Base.opDispatch!("s", int, Foo) error instantiating" and I have no clue why. Does it work if you remove `protected` from the derived class? Yes, but why should the derived class not have access to it?
Re: Filter for opDispatch?
On Saturday, 15 May 2021 at 23:41:19 UTC, frame wrote: On Friday, 14 May 2021 at 23:02:22 UTC, frame wrote: Thanks! I stumbled around with static asserts and mixins... totally forgot about the constraints but they will to the trick. Now I run into the error "class Foo member s is not accessible" "template instance Base.opDispatch!("s", int, Foo) error instantiating" and I have no clue why. Does it work if you remove `protected` from the derived class?
Re: Filter for opDispatch?
On Friday, 14 May 2021 at 23:02:22 UTC, frame wrote: Thanks! I stumbled around with static asserts and mixins... totally forgot about the constraints but they will to the trick. Now I run into the error "class Foo member s is not accessible" "template instance Base.opDispatch!("s", int, Foo) error instantiating" and I have no clue why. I swear the original code is just simple as that and satisfyDispatch works fine (there is no problem if I change s to a simple field). ```d abstract class Base { void opDispatch(string property, S, this T)(auto ref S v) // if (satisfyDispatch!(T, property)) { __traits(getMember, cast(T) this, property) = v; // error reported here } auto opDispatch(string property, this T)() // if (satisfyDispatch!(T, property)) { return __traits(getMember, cast(T) this, property); } } // other module class Foo : Base { protected: int _s; // int s; // would work void s(int v) { _s = v; } int s() { return _s; } } // called from a method like this: void updateValue(T, V)(V value, Object object) { (cast(T) object).opDispatch!(property)(value); } ``` I first thought the compiler does a recursive call on __traits(getMember) but it has no problems with this simple code above.
Re: ugly and/or useless features in the language.
On Saturday, 15 May 2021 at 14:31:08 UTC, Alain De Vos wrote: Feature creep can make your own code unreadable. Having many ways to express the same concept makes code harder to read. This is an issue in C++, but you can combat it by creating coding norms. In general it is better to have fewer features and instead improve metaprogramming so that missing features can be done in a library. Also some features could be merged, like alias and enum constants.
Re: struct destructor
On Saturday, 15 May 2021 at 18:26:08 UTC, Adam D. Ruppe wrote: On Saturday, 15 May 2021 at 17:55:17 UTC, Alain De Vos wrote: Feature request, a function old which does the opposite of new, allowing deterministic,real-time behavior and memory conservation. You're best off doing malloc+free if you want complete control though. You can use the heapAlloc / heapFree pair: https://wiki.dlang.org/Memory_Management#Explicit_Class_Instance_Allocation Which I added to my package here :-) https://code.dlang.org/packages/jdiutil https://github.com/mingwugmail/jdiutil/blob/master/source/jdiutil/memory.d
Re: struct destructor
I'll try first the first tip of Adam, here the code, ``` import std.stdio:writeln; import core.memory: GC; void myfun(){ class C{ int[1] x; }//class C struct S { C c=null; @disable this(); this(int dummy) { c=new C(); writeln("Constructor"); };//Constructor ~this(){ writeln("Destructor"); .destroy(c); void * address=GC.addrOf(cast(void *)c); GC.free(address); };//destructor }//struct S S mys=S(0); };//myfun() void main(){ myfun(); };//main ```
Re: struct destructor
On Saturday, 15 May 2021 at 17:55:17 UTC, Alain De Vos wrote: Feature request, a function old which does the opposite of new, allowing deterministic,real-time behavior and memory conservation. You're best off doing malloc+free if you want complete control though.
Re: struct destructor
Sorry free does , indeed.
Re: struct destructor
On Saturday, 15 May 2021 at 18:15:24 UTC, Dennis wrote: On Saturday, 15 May 2021 at 17:55:17 UTC, Alain De Vos wrote: Feature request, a function old which does the opposite of new, allowing deterministic,real-time behavior and memory conservation. You can use [object.destroy](https://dlang.org/phobos/object.html#.destroy) to destruct, and [GC.free](https://dlang.org/phobos/core_memory.html#.GC.free) to free memory allocated with `new`. Specifically you wanna do: ``` .destroy(*ptr); GC.free(GC.addrOf(ptr)); ```
Re: struct destructor
Thanks, good idea but, It does not initiate a GC cycle or free any GC memory.
Re: struct destructor
On Saturday, 15 May 2021 at 17:55:17 UTC, Alain De Vos wrote: Feature request, a function old which does the opposite of new, allowing deterministic,real-time behavior and memory conservation. You can use [object.destroy](https://dlang.org/phobos/object.html#.destroy) to destruct, and [GC.free](https://dlang.org/phobos/core_memory.html#.GC.free) to free memory allocated with `new`.
Re: struct destructor
Feature request, a function old which does the opposite of new, allowing deterministic,real-time behavior and memory conservation.
Re: Recommendations on avoiding range pipeline type hell
On Saturday, 15 May 2021 at 13:46:57 UTC, Chris Piker wrote: I'm trying to do that, but range3 and range2 are written by me not a Phobos wizard, and there's a whole library of template functions a person needs to learn to make their own pipelines. For example: Phobos has plenty of design flaws, you don't want to copy that. Generally you should just accept the range with a simple foreach in your handler. ``` void processRange(R)(R r) { foreach(item; r) { // use item } } ``` If you want it forwarded in a pipeline, make a predicate that works on an individual item and pass it to `map` instead of trying to forward everything. If you're creating a range, only worry about the basic three functions: empty, front, and popFront. That's the minimum then it works with most phobos things too. That's where I balance ease of use with compatibility - those three basics let the phobos ones iterate through your generated data. Can't jump around but you can do a lot with just that. (personally btw I don't even use most of this stuff at all) // ... what's with the . before the ElementType statement? Now that is good to know: that is a D language thing meaning "look this up at top level". So like let's say you are writing a module with ``` void func(); class Foo { void func(); void stuff() { func(); } } ``` The func inside stuff would normally refer to the local method; it is shorthand for `this.func();`. But what if you want that `func` from outside the class? That's where the . comes in: ``` void func(); class Foo { void func(); void stuff() { .func(); // now refers to top-level, no more `this` } } ``` In fact, it might help to think of it as specifically NOT wanting `this.func`, so you leave the this out. What the heck is that? idk i can't read that either, the awful error message are one reason why i don't even use this style myself (and the other is im just not on the functional bandwagon...) Most the time std.algorithm vomits though it is because some future function required a capability that got dropped in the middle. For example: some_array.filter.sort would vomit because sort needs random access, but filter drops that. So like sort says "give me the second element" but filter doesn't know what the second element is until it actually processes the sequence - it might filter out ALL the elements and it has no way of knowing if anything is left until it actually performs the filter. And since all these algorithms are lazy, it puts off actually performing anything until it has some idea what the end result is supposed to be. The frequent advice here is to stick ".array" in the middle, which performs the operation up to that point and puts the result in a freshly-created array. This works, but it also kinda obscures why it is there and sacrifices the high performance the lazy pipeline is supposed to offer, making it process intermediate data it might just discard at the next step anyway. Rearranging the pipeline so the relatively destructive items are last can sometimes give better results. (But on the other hand, sorting 100,000 items when you know 99,000 are going to be filtered out is itself wasted time... so there's no one right answer.) anyway idk what's going on in your case. it could even just be a compile error in a predicate, like a typo'd name. it won't tell you, it just vomits up so much spam it could fill a monty python sketch. messages. (Using interfaces or *gasp* casts, would break the TMI situation.) i <3 interfaces it is a pity to me cuz D's java-style OOP is actually pretty excellent. a few little things I'd fix if I could, a few nice additions I could dream up, but I'm overall pretty happy with it and its error messages are much better. but too many people in the core team are allergic to classes. and i get it, classes do cost you some theoretical performance, and a lot of people's class hierarchies are hideous af, but hey they work and give pretty helpful errors. Most the time. better know all of std.traits and std.meta cause you're going to need them too implement a range-of-ranges consumer. Write your function like it is Python or javascript - use the properties you want on an unconstrained template function. void foo(T)(T thing) { // use thing.whatever // or thing[whatever] // or whatever you need } Even if that's a range of ranges: void foo(T)(T thing) { foreach(range; thing) foreach(item; range) // use item. } It will work if you actually get a range of ranges and if not, you get an error anyway. It isn't like the constraint ones are readable, so just let this fail where it may. (In fact, I find the non-contraint messages to be a little better! I'd rather see like "cannot foreach over range" than "no match for ") I don't even think phobos benefits from its traits signatures. If you do it
Re: struct destructor
On Saturday, 15 May 2021 at 16:53:04 UTC, Adam D. Ruppe wrote: On Saturday, 15 May 2021 at 16:52:10 UTC, Alain De Vos wrote: When I do a "new" in a struct constructor to assign to a member variable of this struct, what do i write in the same struct destructor to free the memory ? If you used `new` the garbage collector is responsible for it. Can I send a kind message to the garbage collector to please free that speficic memory at that time specified ?
struct destructor
When I do a "new" in a struct constructor to assign to a member variable of this struct, what do i write in the same struct destructor to free the memory ?
Re: struct destructor
On Saturday, 15 May 2021 at 16:52:10 UTC, Alain De Vos wrote: When I do a "new" in a struct constructor to assign to a member variable of this struct, what do i write in the same struct destructor to free the memory ? If you used `new` the garbage collector is responsible for it.
Re: Recommendations on avoiding range pipeline type hell
On 5/15/21 4:25 AM, Chris Piker wrote: > But, loops are bad. I agree with Adam here. Although most of my recent code gravitates towards long range expressions, I use 'foreach' (even 'for') when I think it makes code more readable. > Is there some obvious trick or way of looking at the problem that I'm > missing? The following are idioms that I use: * The range is part of the type: struct MyType(R) { R myRange; } * If the type is too complicated as in your examples: struct MyType(R) { R myRange; } auto makeMyType(X, Y)(/* ... */) { auto myArg = foo!X.bar!Y.etc; return MyType!(typeof(myArg))(myArg); } * If my type can't be templated: struct MyType { alias MyRange = typeof(makeMyArg()); MyRange myRange; } // For the alias to work above, all parameters of this // function must have default values so that the typeof // expression is as convenient as above. auto makeMyArg(X, Y)(X x = X.init, Y y = Y.init) { // Then, you can put some condition checks here if // X.init and Y.init are invalid values for your // program. return foo!X.bar!Y.etc; } I think that's all really. And yes, sometimes there are confusing error messages but the compiler is always right. :) Ali
ugly and/or useless features in the language.
Which parts in dlang don't you use and why ? Personally i have no need for enum types, immutable is doing fine. Auto return types i find dangerous to use. Voldermont types. Named initialiser. Tuple features. Maybe some other ? Feature creep can make your own code unreadable. Offcourse taste can very from person to person.
Re: Scope of import
On Saturday, 15 May 2021 at 11:38:22 UTC, Adam D. Ruppe wrote> Just use ``` dmd -i main.d instead. It will be about 2x faster and more reliable. ``` Your suggestion worked. Thank you.
Re: Recommendations on avoiding range pipeline type hell
On Saturday, 15 May 2021 at 14:05:34 UTC, Paul Backus wrote: If you post your code (or at least a self-contained subset of it) someone can probably help you figure out where you're running into trouble. Smart idea. It's all on github. I'll fix a few items and send a link soon as I get a little shut eye. all I can say from them is, "you must be doing something wrong." I bet you're right :) Take Care,
Re: Recommendations on avoiding range pipeline type hell
On Saturday, 15 May 2021 at 13:43:29 UTC, Mike Parker wrote: On Saturday, 15 May 2021 at 11:25:10 UTC, Chris Piker wrote: In addition to what Adam said, if you do need to store the result for use in a friendlier form, just import `std.array` and append `.array` to the end of the pipeline. This will eagerly allocate space for and copy the range elements to an array, i.e., convert the range to a container: Thanks for the suggestion. Unfortunately the range is going to be 40+ years of Voyager magnetometer data processed in a pipeline. I am trying to do everything in functional form, but the deep type dependencies (and my lack of knowledge) are crushing my productivity. I might have to stop trying to write idiomatic D and start writing Java-in-D just to move this project along. Fortunately, D supports that too.
Re: Recommendations on avoiding range pipeline type hell
On Saturday, 15 May 2021 at 13:46:57 UTC, Chris Piker wrote: Every time I slightly change the inputs to range2, then a function that operates on *range3* output types blows up with a helpful message similar to: [snip] If you post your code (or at least a self-contained subset of it) someone can probably help you figure out where you're running into trouble. The error messages by themselves do not provide enough information--all I can say from them is, "you must be doing something wrong."
Re: Recommendations on avoiding range pipeline type hell
On Saturday, 15 May 2021 at 11:25:10 UTC, Chris Piker wrote: Thanks for your patience with a potentially dumb question. I've been working on the code for well over 12 hours so I'm probably not thinking straight it this point. BTW, I can send you a couple of documents regarding ranges that you may or may not find useful. Please email me at aldac...@gmail.com if you're interested.
Re: Recommendations on avoiding range pipeline type hell
On Saturday, 15 May 2021 at 11:51:11 UTC, Adam D. Ruppe wrote: On Saturday, 15 May 2021 at 11:25:10 UTC, Chris Piker wrote: The idea is you aren't supposed to care what the type is, just what attributes it has, e.g., can be indexed, or can be assigned, etc. (Warning, new user rant ahead. Eye rolling warranted and encouraged) I'm trying to do that, but range3 and range2 are written by me not a Phobos wizard, and there's a whole library of template functions a person needs to learn to make their own pipelines. For example: ```d // From std/range/package.d CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges)) alias RvalueElementType = CommonType!(staticMap!(.ElementType, R)); // ... what's with the . before the ElementType statement? Line 921 says // .ElementType depends on RvalueElementType. How can they depend on // each other? Is this a recursive template thing? ``` and all the other automagic stuff that phobos pulls off to make ranges work. If that's what's needed to make a custom range type, then D ranges should come with the warning **don't try this at home**. (Ali's book made it look so easy that I got sucker in) Every time I slightly change the inputs to range2, then a function that operates on *range3* output types blows up with a helpful message similar to: ``` template das2.range.PrioritySelect!(PriorityRange!(DasRange!(Tuple!(int, int)[], int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int), int function() pure nothrow @nogc @safe), PriorityRange!(DasRange!(Tuple!(int, int)[], int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int), int function() pure nothrow @nogc @safe)).PrioritySelect.getReady.filter!((rng) => !rng.empty).filter cannot deduce function from argument types !()(PriorityRange!(DasRange!(Tuple!(int, int)[], int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int), int function() pure nothrow @nogc @safe), PriorityRange!(DasRange!(Tuple!(int, int)[], int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int), int function() pure nothrow @nogc @safe)) ``` What the heck is that? Anyway, you put it all in one bit thing and this is kinda important: avoid assigning it to anything. You'd ideally do all the work, from creation to conclusion, all in the big pipeline. I fell back to using assignments just to make sure range2 values were saved in a concrete variable so that range3 didn't break when I changed the lambda that was run by range2 to mutate it's output elements. What went in to getting the element to range3's doorstep is a detail that I shouldn't have to care about inside range3 code, but am forced to care about it, because changing range2's type, changes range3's type and triggers really obscure error messages. (Using interfaces or *gasp* casts, would break the TMI situation.) So say you want to write it auto mega_range = range1.range2!(lambda2).range3!(lambda3); writeln(mega_range); that'd prolly work, writeln is itself flexible enough, but you'd prolly be better off doing like Sure it will work, because writeln isn't some function written by a new user, it's got all the meta magic. This way the concrete type never enters into things, it is all just a detail the compiler tracks to ensure the next consumer doesn't try to do things the previous step does not support. It's all just a detail the compiler tracks, until you're not sending to writeln, but to your own data consumer. Then, you'd better know all of std.traits and std.meta cause you're going to need them too implement a range-of-ranges consumer. And by the way you have to use a range of ranges instead of an array of ranges because two ranges that look to be identical types, actually are not identical types and so can't go into the same array. Here's an actual (though formatted by me) error message I got stating that two things were different and thus couldn't share an array. Can you see the difference? I can't. Please point it out if you do. ```d das2/range.d(570,39): Error: incompatible types for (dr_fine) : (dr_coarse): das2.range.PriorityRange!( DasRange!( Take!( ZipShortest!( cast(Flag)false, Result, Generator!(function () @safe => uniform(0, 128)) ) ), int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int ), int function() pure nothrow @nogc @safe ) and das2.range.PriorityRange!( DasRange!( Take!( ZipShortest!( cast(Flag)false, Result, Generator!(function () @safe => uniform(0, 128)) ) ), int function(Tuple!(int, int)) pu
Re: Recommendations on avoiding range pipeline type hell
On Saturday, 15 May 2021 at 11:25:10 UTC, Chris Piker wrote: Is there some obvious trick or way of looking at the problem that I'm missing? In addition to what Adam said, if you do need to store the result for use in a friendlier form, just import `std.array` and append `.array` to the end of the pipeline. This will eagerly allocate space for and copy the range elements to an array, i.e., convert the range to a container: ```d auto mega_range = range1.range2!(lambda2).range3!(lambda3).array; ``` Sometimes you may want to set up a range and save it for later consumption, but not necessarily as a container. In that case, just store the range itself as you already do, and pass it to a consumer when you're ready. That might be `.array` or it could be `foreach` or something else. ```d auto mega_range = range1.range2!(lambda2).range3!(lambda3); // later foreach(elem; mega_range) { doStuff(elem); } ```
Re: Scope of import
In unix i give the compiler: ``` ldc2 `find . -name \*.d -print` ``` So he always takes all sourcefiles
Re: Scope of import
On Saturday, 15 May 2021 at 11:46:49 UTC, Dennis wrote: You can do `dmd -i -run main.d` Yeah but that's weird with how it handles arguments and without the compilation cache it gets really annoying to use.
Re: Recommendations on avoiding range pipeline type hell
On Saturday, 15 May 2021 at 11:25:10 UTC, Chris Piker wrote: Then the type definition of mega_range is something in the order of: The idea is you aren't supposed to care what the type is, just what attributes it has, e.g., can be indexed, or can be assigned, etc. You'd want to do it all in one big statement, with a consumer at the end (and pray there's no errors cuz while you're supposed to hide from the type, it won't hide from you if there's a problem, and as you know the errors might be usable if they were formatted better and got to the point but they're not and sometimes the compiler withholds vital information from you! Error message quality is D's #1 practical problem. but ill stop ranting) Anyway, you put it all in one bit thing and this is kinda important: avoid assigning it to anything. You'd ideally do all the work, from creation to conclusion, all in the big pipeline. So say you want to write it auto mega_range = range1.range2!(lambda2).range3!(lambda3); writeln(mega_range); that'd prolly work, writeln is itself flexible enough, but you'd prolly be better off doing like ``` range1 .range2!lambda2 .range3!lambda3 .each!writeln; // tell it to write out each element ``` Or since writeln is itself a range consumer you could avoid that .each call. But it is really useful for getting the result out of a bit mess for a normal function that isn't a full range consumer. (It is basically foreach written as a function call instead of as a loop) This way the concrete type never enters into things, it is all just a detail the compiler tracks to ensure the next consumer doesn't try to do things the previous step does not support. But, loops are bad. On the D blog I've seen knowledgeable people say all loops are bugs. Meh, don't listen to that nonsense, just write what works for you. D's strength is that it adapts to different styles and meets you where you are. Listening to dogmatic sermons about idiomatic one true ways is throwing that strength away and likely to kill your personal productivity as you're fighting your instincts instead of making it work.
Re: Scope of import
On Saturday, 15 May 2021 at 11:38:22 UTC, Adam D. Ruppe wrote: * rdmd runs the program too, dmd -i just compiles. You run the program separately. You can do `dmd -i -run main.d`
Re: Scope of import
On Saturday, 15 May 2021 at 07:15:51 UTC, DLearner wrote: rdmd main.d rdmd sucks, it runs the compiler twice and get the list of imports and even then it might not see them all. Just use dmd -i main.d instead. It will be about 2x faster and more reliable. The downside differences though: * rdmd runs the program too, dmd -i just compiles. You run the program separately. * rdmd will cache the executable, dmd -i will always recompile. But since running the program is a separate step, you just run it yourself if you don't want to recompile, and run dmd if you do.
Recommendations on avoiding range pipeline type hell
Hi D Since the example of piping the output of one range to another looked pretty cool, I've tried my own hand at it for my current program, and the results have been... sub optimal. Basically the issue is that if one attempts to make a range based pipeline aka: ```d auto mega_range = range1.range2!(lambda2).range3!(lambda3); ``` Then the type definition of mega_range is something in the order of: ```d TYPE_range3!( TYPE_range2!( TYPE_range1, TYPE_lamba2 ), TYPE_lambda3)); ``` So the type tree builds to infinity and the type of `range3` is very much determined by the lambda I gave to `range2`. To me this seems kinda crazy. To cut through all the clutter, I need something more like a unix command line: ```bash prog1 | prog2 some_args | prog3 some_args ``` Here prog2 doesn't care what prog1 *is* just what it produces. So pipelines that are more like: ```d ET2 front2(ET1, FT)(ET1 element, FT lambda){ /* stuff */ } ET3 front3(ET2, FT)(ET2 element, FT lambda){ /* stuff */ } void main(){ for(; !range1.empty; range1.popFront() ) { ET3 el3 = front3( front2(range1.front, lambda2), lamda3) ); writeln(el3); } } ``` But, loops are bad. On the D blog I've seen knowledgeable people say all loops are bugs. But how do you get rid of them without descending into Type Hell(tm). Is there anyway to get some type erasure on the stack? The only thing I can think of is to use Interfaces and Classes like Java, but we don't have the automagical JVM reordering the heap at runtime, so that means living life on a scattered heap, just like python. Is there some obvious trick or way of looking at the problem that I'm missing? Thanks for your patience with a potentially dumb question. I've been working on the code for well over 12 hours so I'm probably not thinking straight it this point. Cheers all,
Re: Any suggestions on dmd error message formatting?
On Saturday, 15 May 2021 at 09:09:36 UTC, Berni44 wrote: ... Honestly, even having a dumb formatter that puts things like this would be 100x more useable than what we currently get: ```d das2.range.PriorityRange!( DasRange!( Take!( ZipShortest!( cast(Flag)false, Result, Generator!( function ( ) @safe => uniform( 0, 128 ) ) ) ), int function( Tuple!( int, int ) ) pure nothrow @nogc @safe, int function( Tuple!( int, int ) ) pure nothrow @nogc @safe, Tuple!( int, int ), int ), int function( ) pure nothrow @nogc @safe ) ```
Re: What is the difference between these template declaration forms?
On Saturday, 15 May 2021 at 08:37:21 UTC, cc wrote: Are these identical? Or is there a different usage for the (T : something) form? ```d auto opCast(T)() if (is(T == bool)) { return _obj !is null; } ``` They are the same in this case. ```d auto opCast(T : bool)() { return _obj !is null; } ``` While the docs says it matches the most specialized type, which is bool in this case, IIRC it is actually takes anything convertible to bool despite what the docs says. You should double check it yourself. Anyway I would usually pick this form where possible as it yields cleaner error messages unlike arbitrary template constraint "stuff X doesnt takes Y, did you mean (basically X but not)" message that who knows what it wants you to do.
Re: Any suggestions on dmd error message formatting?
On Saturday, 15 May 2021 at 08:15:19 UTC, Chris Piker wrote: I did much the same as you and reformatted the error message to find the bug. As to the larger question of how to automatically process compiler output... got any ideas? Hope someone who knows how to modify DMD bothers to: 1. Implement some kind of ability for that to work. 2. Convinces Walter to let it through. I can't do either, so just have to hope this issue is finally tackled at some point in the future. My guess is that the `Result` item is a hint. `Result` probably never equals another `Result` no matter what. Yea, I can't see what's wrong just from that either. My best guess is `Result` might be embedded within another templated thing, which might be different than the `Result` that the function is expecting. Place a couple of `pragma(msg, Result.stringof); // Might need to use typeof(Result).stringof, or even __traits(identifier, Result)` wherever it might be relevant, and see if that shows anything fun. I also really can't see where else there'd be a type mismatch, especially if a `.array` is what fixes things. e.g. `RangeThatReturns!OtherRange.Result != RangeThatReturns!(int[]).Result` But other than that, I can't tell just from that error snippet.
Re: Any suggestions on dmd error message formatting?
On Saturday, 15 May 2021 at 04:54:15 UTC, Chris Piker wrote: As always, your advice is much appreciated I'm usually piping the results through hexdump. ;-) No, in earnest, I often would have liked to have better formatted messages. The only thing I can say: Sometimes it helps to increase the size of the window (>300 columns or so). Without line breaking, sometimes you can spot patterns you didn't before...
What is the difference between these template declaration forms?
Are these identical? Or is there a different usage for the (T : something) form? ```d auto opCast(T)() if (is(T == bool)) { return _obj !is null; } ``` ```d auto opCast(T : bool)() { return _obj !is null; } ```
Re: Any suggestions on dmd error message formatting?
On Saturday, 15 May 2021 at 06:12:25 UTC, SealabJaster wrote: On Saturday, 15 May 2021 at 04:54:15 UTC, Chris Piker wrote: T_T My eyes burn. Good, it's not just me. If figured the Deities out there visually parse these messages even hung over. Seems the final `int function` parameter needs to accept a `Tuple!(int, int)` I did much the same as you and reformatted the error message to find the bug. As to the larger question of how to automatically process compiler output... got any ideas? Hey since you're pretty good at this, can you tell me why how a person fixes this error? I've already formatted it, but I haven't changed any of the non-whitespace text. ``` das2/range.d(570,39): Error: incompatible types for (dr_fine) : (dr_coarse): ``` ```d das2.range.PriorityRange!( DasRange!( Take!( ZipShortest!( cast(Flag)false, Result, Generator!(function () @safe => uniform(0, 128)) ) ), int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int ), int function() pure nothrow @nogc @safe ) and das2.range.PriorityRange!( DasRange!( Take!( ZipShortest!( cast(Flag)false, Result, Generator!(function () @safe => uniform(0, 128)) ) ), int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int ), int function() pure nothrow @nogc @safe ) ``` To get around the problem I used `.array` for a bit of type erasure, so for now this error isn't messing with my unittests, but danged if I can spot the problem, even formatted. My guess is that the `Result` item is a hint. `Result` probably never equals another `Result` no matter what.
Re: Scope of import
On Saturday, 15 May 2021 at 07:15:51 UTC, DLearner wrote: On Saturday, 15 May 2021 at 07:05:00 UTC, Mike Parker wrote: That's odd. What's your command line? rdmd main.d Okay, so it's definitely a bug in rdmd. Change module A to look like this and it works properly: ```d module A; import B; void fnA1() { import std.stdio; writeln("Entered fnA1"); fnB1(); writeln("Leaving fnA1"); } ```
Re: Scope of import
On Saturday, 15 May 2021 at 07:19:08 UTC, Mike Parker wrote: Then it must be an issue with rdmd... rdmd build 20210311 Running under Win-10.
Re: Scope of import
On Saturday, 15 May 2021 at 07:05:00 UTC, Mike Parker wrote: That's odd. What's your command line? rdmd main.d
Re: Scope of import
On Saturday, 15 May 2021 at 07:15:51 UTC, DLearner wrote: On Saturday, 15 May 2021 at 07:05:00 UTC, Mike Parker wrote: That's odd. What's your command line? rdmd main.d Then it must be an issue with rdmd. The following both work as expected, whether your the `import B;` in `main` is commented out or not: dmd -i main.d dmd main.d A.d B.d
Re: Scope of import
On Saturday, 15 May 2021 at 06:55:47 UTC, DLearner wrote: 1. Code above compiles but fails on linker step with 'Error 42 Symbol Undefined'. To me, unexpected behaviour as imports arranged to pick up symbols (with minimum scope). Your error is a linker error. Imports have nothing to do with the linker. They are for the compiler to know which symbols are available in the module it's currently compiling. But every symbol that you use needs to be linked by the linker, and that's a separate step. 2. Uncommenting the 'import B' in main everything works correctly. That's odd. What's your command line? To me, particularly unexpected behaviour as no symbol from B directly used in main (also undesirable to set scope unnecessarily wide). Whether you use a symbol in main or not is irrelevant to the linker. Any symbol accessed anywhere in your program must ultimately be linked in.
Scope of import
``` // main void main() { import A; // import B; import std.stdio; writeln("Entered main"); fnA1(); writeln("Leaving main"); } ``` ``` module A; void fnA1() { import B; import std.stdio; writeln("Entered fnA1"); fnB1(); writeln("Leaving fnA1"); } ``` ``` module B; void fnB1() { import std.stdio; writeln("Entered fnB1"); writeln("Leaving fnB1"); } ``` 1. Code above compiles but fails on linker step with 'Error 42 Symbol Undefined'. To me, unexpected behaviour as imports arranged to pick up symbols (with minimum scope). 2. Uncommenting the 'import B' in main everything works correctly. To me, particularly unexpected behaviour as no symbol from B directly used in main (also undesirable to set scope unnecessarily wide). Best regards