Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 10:06:11 UTC, Jack Applegame wrote: Here's another way using ``` std.typecons ``` ```d import std.stdio; import std.typecons; alias input = Typedef!int; //new code struct Field { void opAssign(int a) { writefln("Field.opAssign(%s)", a); } } struct Register { Field clock(input a) { writefln("Register.clock(%s)", cast(int)a); //note the cast return Field(); } } void main() { input ip = 1; Register register; register.clock(ip) = 10; // works, good //register.clock = 10;// works too, how to disable it? EDIT: Now it doesn't work :) } ``` You will have to either cast your literal, or provide a variable with the new type as input though, so it is also not perfect.
Re: to compose or hack?
On Wednesday, 7 July 2021 at 01:44:20 UTC, Steven Schveighoffer wrote: This is pretty minimal, but does what I want it to do. Is it ready for inclusion in Phobos? Not by a longshot! A truly generic interleave would properly forward everything else that the range supports (like `length`, `save`, etc). But it got me thinking, how often do people roll their own vs. trying to compose using existing Phobos nuggets? I found this pretty satisfying, even if I didn't test it to death and maybe I use it only in one place. Do you find it difficult to use Phobos in a lot of situations to compose your specialized ranges? I try to compose using existing Phobos facilities, but don't hesitate to write my own ranges. The reasons are usually along the lines you describe. For one, range creation is easy in D, consistent with the pro/con tradeoffs described in the thread/talk [Iterator and Ranges: Comparing C++ to D to Rust](https://forum.dlang.org/thread/diexjstekiyzgxlic...@forum.dlang.org). Another is that if application/task specific logic is involved, it is often simpler/faster to just incorporate it into the range rather than figure out how to factor it out of the more general range. Especially if the range is not going to be used much. --Jon
to compose or hack?
So I have this situation where I need to split a string, then where the splits are, insert a string to go between the elements making a new range, all without allocating (hopefully). Looking around phobos I found inside the documentation of [roundRobin](https://dlang.org/phobos/std_range.html#.roundRobin) something that does *exactly* what I'm looking for. Except... the provided `interleave` function iterates the original range twice, which means 2x the searching calls for splitter. Why does it do this? Because `roundRobin` will keep going as long as ANY range still has data left, so you need to make the "interleaving" range stop when the first one stops. After struggling to think up ways to compose this (hm.., can I make the ranges share a stopping point?) without the 2x penalty, I just decided to write my own interleave range which does exactly what I am looking for: ```d auto interleave(R, U)(R src, U middles) if (isInputRange!R && is(U == ElementType!R)) { static struct Result { R src; U middles; bool between = false; auto front() { assert(!empty); return between ? middles : src.front; } void popFront() { assert(!empty); if(between) between = false; else { src.popFront; between = true; } } bool empty() { return src.empty; } } return Result(src, middles); } ``` This is pretty minimal, but does what I want it to do. Is it ready for inclusion in Phobos? Not by a longshot! A truly generic interleave would properly forward everything else that the range supports (like `length`, `save`, etc). But it got me thinking, how often do people roll their own vs. trying to compose using existing Phobos nuggets? I found this pretty satisfying, even if I didn't test it to death and maybe I use it only in one place. Do you find it difficult to use Phobos in a lot of situations to compose your specialized ranges? Oh, and if you do know of a better way to compose the range that doesn't require the double iteration, I'd be interested in seeing it. -Steve
Re: Find a char among string (string.findAmong.char)
On Tuesday, 6 July 2021 at 15:48:35 UTC, rassoc wrote: You can also do: ```d import std; void main() { // https://dlang.org/phobos/std_ascii.html#.lowercase "Book.".filter!(c => lowercase.canFind(c)) .each!(c => writeln(c, " found")); // Output: // o found // o found // k found } ``` I really don't like reading arrow functions. It takes some more effort to understand, follow and get used to them. I'd like something simple and effortless looking and feeling that would make code readable similarly to an english sentence. Such as this, but as noted, this does not work as intended/assumed by me: ``` if (letter.findAmong(alphabet)){ write("found"); } ```
Re: Find a char among string (string.findAmong.char)
You can also do: ```d import std; void main() { // https://dlang.org/phobos/std_ascii.html#.lowercase "Book.".filter!(c => lowercase.canFind(c)) .each!(c => writeln(c, " found")); // Output: // o found // o found // k found } ```
Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 15:24:37 UTC, jfondren wrote: 3. https://run.dlang.io/is/AJM6Vg - hybrid where ClockAssign has an unsafe pointer that the compiler complains about :/ 4. ```d import std.stdio; struct Field { void opAssign(int a) { writefln("Field.opAssign(%s)", a); } } struct ClockAssign { Field[] clocks; void opIndexAssign(int a, int b) { writefln("Register.clock(%s)", a); clocks ~= Field(); clocks[$-1] = b; } } struct Register { ClockAssign clock; } void main() { Register register; register.clock[1] = 10; // register.clock = 10; // error } ```
Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 10:06:11 UTC, Jack Applegame wrote: How to disable `register.clock = 10;` but allow `register.clock(1) = 10;`? I want to get a compilation error on `register.clock = 10;` Some options: 1. return a temporary struct with an opIndex ```d import std.stdio; struct Field { void opAssign(int a) { writefln("Field.opAssign(%s)", a); } } struct ClockAssign { Field opIndex(int a) { writefln("Register.clock(%s)", a); return Field(); } } struct Register { ClockAssign clock() { return ClockAssign(); } } void main() { Register register; register.clock[1] = 10; // works, good //register.clock = 10; // error } ``` 2. https://run.dlang.io/is/bkV64U - keep track of fields and fail at runtime if a field was never initialized (because it was silently discarded in this case). 3. https://run.dlang.io/is/AJM6Vg - hybrid where ClockAssign has an unsafe pointer that the compiler complains about :/
Re: Getting resulting/return type from operation in templates
On Tuesday, 6 July 2021 at 15:00:24 UTC, Paul Backus wrote: On Tuesday, 6 July 2021 at 14:43:26 UTC, Rekel wrote: Is there any reason the function call in the alias is acceptable? I would imagine the () part would actually require 2 parameters. You're right, it does; that was a mistake on my part. It should work with `Lhs.init` and `Rhs.init` as arguments. Hmm . . . doing that ironically brings me back to using: ```d alias ResultType(Lhs, string op, Rhs) = typeof(mixin("Lhs.init" ~ op ~ "Rhs.init")); auto opBinary(string op, R: T2[], T2)(R right) const if (is(ResultType!(T, op, T2))) { Vec!(ResultType!(T, op, T2), L) result; static foreach (i; 0 .. L) { mixin("result[i] = this[i] " ~ op ~ " right[i];"); } return result; } ``` Kind of ironic this is basically an alias of my old solution. Strangely enough the nanF issue went away though, I guess I misinterpreted this. Thanks for your help anyway 😅
Re: Getting resulting/return type from operation in templates
On Tuesday, 6 July 2021 at 14:43:26 UTC, Rekel wrote: Is there any reason the function call in the alias is acceptable? I would imagine the () part would actually require 2 parameters. You're right, it does; that was a mistake on my part. It should work with `Lhs.init` and `Rhs.init` as arguments.
Re: How to disable assigning a value to a property?
On 7/6/21 9:27 AM, Jack Applegame wrote: On Tuesday, 6 July 2021 at 12:33:20 UTC, Adam D Ruppe wrote: The language always allows `a = b;` to be rewritten as `a(b);`. And that's sad. It should happen for properties only. Yes, I lament that there is no way to control how people call your function. It can result in surprising things, and it means as a library designer you have to consider this usage when picking names. There are a few "draft" DIP proposals (under the old DIP system) here: https://wiki.dlang.org/DIPs But I think the time of being able to make such a disruptive change has passed. For better or worse we have the half-implemented near-useless meaning of `@property`, and basically it's unneeded. -Steve
Re: Getting resulting/return type from operation in templates
On Tuesday, 6 July 2021 at 14:27:35 UTC, Paul Backus wrote: Instead of having the template evaluate to a `bool`, have it evaluate to the type of the result: ```d alias ResultType(Lhs, string op, Rhs) = typeof(((Lhs lhs, Rhs rhs) => mixin("lhs", op, "rhs"))()); static assert(is(ResultType!(int, "+", double) == double)); static assert(is(ResultType!(string, "~", string) == string)); static assert(!is(ResultType!(string, "+", int))); // no valid result type ``` Then you can use `is()` in the template constraints to check whether the operation is supported: ```d auto opBinary(string op, Rhs: T2[], T2) const if (is(ResultType!(T, op, T2))) { Vec!(ResultType!(T, op, T2), L) result; // etc. } ``` Oh that's neat, thanks. I guess that would make it: ```d auto opBinary(string op, R)(R right) const if (is(ResultType!(T, op, R))) { Vec!(ResultType!(T, op, R), L) result; static foreach (i; 0 .. L) { mixin("result[i] = this[i] " ~ op ~ " right;"); } return result; } ``` I guess I'll just have to take the result definition for what it is. At least the return type can use auto, haha. Imagine using ResultType!(T, op, R) thrice... Is there any reason the function call in the alias is acceptable? I would imagine the () part would actually require 2 parameters.
Re: Getting resulting/return type from operation in templates
On Tuesday, 6 July 2021 at 14:12:48 UTC, Rekel wrote: I recently found __traits(compiles, ...) can be used in template constraints. (I first used `is(mixin("T.init"~op~"T2.init"))` but this cause problems related to nanF) However I'm wondering if there is an easier way to do what I'm currently doing, especially since using typeof inside the result declaration is quite cumbersome. This is a bigger problem in my less-simplified code (using matrices), where it starts getting slightly unreadable. It also assumes the presence of .vec[0] (not necessarily a problem here but it seems like a codesmell) Simplified: ```d template supported(A, string op, B) { const bool supported = __traits(compiles, (A a, B b) { mixin("return a" ~ op ~ "b;"); }); } ``` Instead of having the template evaluate to a `bool`, have it evaluate to the type of the result: ```d alias ResultType(Lhs, string op, Rhs) = typeof(((Lhs lhs, Rhs rhs) => mixin("lhs", op, "rhs"))()); static assert(is(ResultType!(int, "+", double) == double)); static assert(is(ResultType!(string, "~", string) == string)); static assert(!is(ResultType!(string, "+", int))); // no valid result type ``` Then you can use `is()` in the template constraints to check whether the operation is supported: ```d auto opBinary(string op, Rhs: T2[], T2) const if (is(ResultType!(T, op, T2))) { Vec!(ResultType!(T, op, T2), L) result; // etc. } ```
Getting resulting/return type from operation in templates
I recently found __traits(compiles, ...) can be used in template constraints. (I first used `is(mixin("T.init"~op~"T2.init"))` but this cause problems related to nanF) However I'm wondering if there is an easier way to do what I'm currently doing, especially since using typeof inside the result declaration is quite cumbersome. This is a bigger problem in my less-simplified code (using matrices), where it starts getting slightly unreadable. It also assumes the presence of .vec[0] (not necessarily a problem here but it seems like a codesmell) Simplified: ```d template supported(A, string op, B) { const bool supported = __traits(compiles, (A a, B b) { mixin("return a" ~ op ~ "b;"); }); } struct Vec(T, uint L) { T[L] vec; alias vec this; auto opBinary(string op, R: T2[], T2)(R right) const if (supported!(T, op, T2)) { Vec!(typeof(mixin("this[0]" ~ op ~ "right[0]")), L) result; static foreach (i; 0 .. L) { mixin("result[i] = this[i] " ~ op ~ " right[i];"); } return result; } auto opBinary(string op, R)(R right) const if (supported!(T, op, R)) { Vec!(typeof(mixin("this[0]" ~ op ~ "right")), L) result; static foreach (i; 0 .. L) { mixin("result[i] = this[i] " ~ op ~ " right;"); } return result; } } void main(string[] args) { Vec!(float, 4) v = Vec!(float, 4)([0, 1, 2, 3]); auto w = v * 2.0; auto x = v + v; auto y = v + [1, 1, 1, 1]; pragma(msg, typeof(w)); // prints "Vec!(double, 4u)" pragma(msg, typeof(x)); // prints "Vec!(float, 4u)" pragma(msg, typeof(y)); // prints "Vec!(float, 4u)" } ```
Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 13:27:43 UTC, Jack Applegame wrote: And that's sad. It should happen for properties only. Totally disagree. This is one of my favorite D features.
Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 12:33:20 UTC, Adam D Ruppe wrote: The language always allows `a = b;` to be rewritten as `a(b);`. And that's sad. It should happen for properties only.
Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 10:06:11 UTC, Jack Applegame wrote: How to disable `register.clock = 10;` You don't. The language always allows `a = b;` to be rewritten as `a(b);`. Best you can do is use different types for the two arguments. Maybe clock could take a struct Clock { int x; } or something instead.
Re: Find a char among string (string.findAmong.char)
On Tuesday, 6 July 2021 at 11:35:14 UTC, BoQsc wrote: I tried out .canFind method, and to test it I removed the letter 'o' from the Alphabet. Weirdly enough .canFind method still found 'o' letter among the Alphabet. https://run.dlang.io/is/2Fvenf Looks like it has something to do with the alias. Static arrays aren't ranges, so you should really be seeing the same error you would if you passed `letters` directly. Change the `canFind` call to take a slice of the array: ```d if (letters[].canFind(letter)){ ``` And it outputs the following as expected: ``` k letter is found among the alphabet. ``` This warrants a bug report with a minimized example.
Re: Find a char among string (string.findAmong.char)
On Monday, 5 July 2021 at 19:48:13 UTC, jfondren wrote: On Monday, 5 July 2021 at 19:34:14 UTC, BoQsc wrote: But I really don't like how it looks less readable and makes less sense on first look. `if (([letter].findAmong(alphabet)).length)` I'd like to use some method on the `letter` instead of [] And `.length` does not make a lot of sense when reading like an english sentence. I suggest canFind, like in my earlier example. findAmong is like "consume this range until you find one of these things, and then return the remainder of the range". It doesn't really fit your use. I tried out .canFind method, and to test it I removed the letter 'o' from the Alphabet. Weirdly enough .canFind method still found 'o' letter among the Alphabet. https://run.dlang.io/is/2Fvenf
Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 10:25:28 UTC, Dennis wrote: We're [still awaiting formal assessment on dip1038](https://forum.dlang.org/thread/sojvxakgruzfvbigz...@forum.dlang.org), but if that gets in, you can mark `clock` or `Field` `@nodicard`. Otherwise I don't know of a way. Yes, it would help.
Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 10:06:11 UTC, Jack Applegame wrote: How to disable `register.clock = 10;` but allow `register.clock(1) = 10;`? I want to get a compilation error on `register.clock = 10;` We're [still awaiting formal assessment on dip1038](https://forum.dlang.org/thread/sojvxakgruzfvbigz...@forum.dlang.org), but if that gets in, you can mark `clock` or `Field` `@nodicard`. Otherwise I don't know of a way.
Re: How to disable assigning a value to a property?
On Tuesday, 6 July 2021 at 10:24:45 UTC, drug wrote: Something like using different types for arguments in `Register.clock` and `Field.opAssign`? I've been thinking about it. Unfortunately, this is not always convenient.
Re: How to disable assigning a value to a property?
06.07.2021 13:06, Jack Applegame пишет: Code: ```d import std.stdio; struct Field {    void opAssign(int a) {    writefln("Field.opAssign(%s)", a);    } } struct Register {    Field clock(int a) {    writefln("Register.clock(%s)", a);    return Field();    } } void main() {    Register register;    register.clock(1) = 10; // works, good    register.clock = 10;   // works too, how to disable it? } ``` How to disable `register.clock = 10;` but allow `register.clock(1) = 10;`? I want to get a compilation error on `register.clock = 10;` Something like using different types for arguments in `Register.clock` and `Field.opAssign`?
How to disable assigning a value to a property?
Code: ```d import std.stdio; struct Field { void opAssign(int a) { writefln("Field.opAssign(%s)", a); } } struct Register { Field clock(int a) { writefln("Register.clock(%s)", a); return Field(); } } void main() { Register register; register.clock(1) = 10; // works, good register.clock = 10;// works too, how to disable it? } ``` How to disable `register.clock = 10;` but allow `register.clock(1) = 10;`? I want to get a compilation error on `register.clock = 10;`