digitalmars.D - ++Phobos
- berni44 (14/14) Oct 16 2019 In the feedback thread H. S. Teoh is talking about that we need a
- Les De Ridder (2/17) Oct 16 2019 Getting rid of autodecoding is another big one.
- rikki cattermole (7/23) Oct 16 2019 I expect to start work on std.eventloop as part of the (informal)
- H. S. Teoh (6/10) Oct 16 2019 What's wrong with isInputRange?
- rikki cattermole (29/41) Oct 16 2019 So these sorts of "functions" are aggregates of behavior and properties
- Jesse Phillips (10/22) Oct 16 2019 The experimental.typecons has an incomplete modification to wrap.
- rikki cattermole (11/42) Oct 16 2019 That works for matching an implementation to an interface.
- Jesse Phillips (6/11) Oct 16 2019 auto foo(R, E = ElementType!R)() if(implements!(InputRange!E, R))
- rikki cattermole (14/29) Oct 16 2019 And that's the problem, for what is very common, it is absolutely
- FeepingCreature (12/21) Oct 17 2019 I still think the only change that is needed is to make the
- Jacob Carlborg (23/52) Oct 17 2019 Can't we just allow structs to implement interfaces and use
- rikki cattermole (10/36) Oct 17 2019 That is a solution yes.
- Atila Neves (3/9) Oct 17 2019 https://github.com/atilaneves/concepts/blob/master/source/concepts/imple...
- Meta (14/25) Oct 17 2019 Correct me if I'm wrong, but would using this with std.range be
- jmh530 (12/26) Oct 17 2019 implements is for an interface. You would actually use models
- Meta (4/34) Oct 17 2019 I'm referring to the InputRange et al. interfaces from
- jmh530 (2/6) Oct 17 2019 Oh sorry. I completely forgot that was in there.
- rikki cattermole (3/33) Oct 17 2019 This unfortunately still ties the implementation itself to the
- Meta (27/45) Oct 18 2019 Not necessarily. I haven't tried this myself, but I think you
- jmh530 (10/15) Oct 18 2019 I don't understand this line:
- Meta (13/30) Oct 18 2019 I wrote that in response to Rikki's assertion:
- jmh530 (14/20) Oct 18 2019 I'm never quite sure whether I grok DbI or not...but all those
- Meta (24/47) Oct 18 2019 Exactly, making it very hard to use @implements from Atila's
- rikki cattermole (42/76) Oct 18 2019 So my problem is with the struct itself knowing about the "interface"
- Paul Backus (7/12) Oct 19 2019 auto map(Args...)(Args arg)
- rikki cattermole (5/17) Oct 19 2019 I am unsure how to respond to this.
- Paul Backus (5/17) Oct 19 2019 I agree that it's a bit ugly. The main advantage is that it's
- Meta (13/61) Oct 19 2019 I assume you're describing ML's signatures, which I'm not
- rikki cattermole (14/32) Oct 19 2019 Swift and Rust can be lumped together (trait + protocols) which I
- Rel (4/19) Oct 17 2019 I'd like Phobos to be something like Go's stdlib in a sence that
- berni44 (13/14) Oct 20 2019 I hoped to be able to summarize all the things, that you wrote,
- rikki cattermole (4/8) Oct 20 2019 I wouldn't worry about it, we can do it incrementally and limit breakage...
In the feedback thread H. S. Teoh is talking about that we need a new/better version of Phobos. I remember having read the same in a comment on some PR recently. How would this better version look like? Is there allready any picture of what we do want? One says, if you don't know the goal, all paths are the wrong ones... A few things that I remember from various sources: * Some improvement in the realm of ranges. * Replacement of some old modules. (std.xml, std.outbuffer, std.socket, what else?) * Adding some missing modules (std.eventloop, std.database, what else?) * Unifying some modules (everything covering selfinspection, like std.traits and so on, whar else?) Anything more?
Oct 16 2019
On Wednesday, 16 October 2019 at 17:20:28 UTC, berni44 wrote:In the feedback thread H. S. Teoh is talking about that we need a new/better version of Phobos. I remember having read the same in a comment on some PR recently. How would this better version look like? Is there allready any picture of what we do want? One says, if you don't know the goal, all paths are the wrong ones... A few things that I remember from various sources: * Some improvement in the realm of ranges. * Replacement of some old modules. (std.xml, std.outbuffer, std.socket, what else?) * Adding some missing modules (std.eventloop, std.database, what else?) * Unifying some modules (everything covering selfinspection, like std.traits and so on, whar else?) Anything more?Getting rid of autodecoding is another big one.
Oct 16 2019
On 17/10/2019 6:20 AM, berni44 wrote:In the feedback thread H. S. Teoh is talking about that we need a new/better version of Phobos. I remember having read the same in a comment on some PR recently. How would this better version look like? Is there allready any picture of what we do want? One says, if you don't know the goal, all paths are the wrong ones... A few things that I remember from various sources: * Some improvement in the realm of ranges. * Replacement of some old modules. (std.xml, std.outbuffer, std.socket, what else?) * Adding some missing modules (std.eventloop, std.database, what else?) * Unifying some modules (everything covering selfinspection, like std.traits and so on, whar else?) Anything more?I expect to start work on std.eventloop as part of the (informal) graphics workgroup soon-ish (although it may not end up as part of Phobos). However my main concern with developing a new version of Phobos is isInputRange and friends will still exist. Unless the language has a better way of describing it e.g. signatures we may as well call it an incremental improvement not a new version.
Oct 16 2019
On Thu, Oct 17, 2019 at 10:59:11AM +1300, rikki cattermole via Digitalmars-d wrote: [...]However my main concern with developing a new version of Phobos is isInputRange and friends will still exist. Unless the language has a better way of describing it e.g. signatures we may as well call it an incremental improvement not a new version.What's wrong with isInputRange? T -- "Hi." "'Lo."
Oct 16 2019
On 17/10/2019 11:16 AM, H. S. Teoh wrote:On Thu, Oct 17, 2019 at 10:59:11AM +1300, rikki cattermole via Digitalmars-d wrote: [...]So these sorts of "functions" are aggregates of behavior and properties that require reading the source code to know fully what it entails. Yes, aggregates of behavior can be complex, and it does make sense to use "functions" to do it. But the key difference here is if you can describe what most of the behaviors and properties are to the compiler it can produce better error messages but also allow code to be more descriptive. I.e. /// Docs go here signature InputRange( named ElementType) { property { /// Docs go here ElementType front(); /// Docs go here bool empty(); } /// Docs go here void popFront(); } void func(T:InputRange)(T myInputRange) {} The above uses DIP1020 just to make this conversation a little easier to understand (ElementType will be inferred automatically from the implementation). And because we have described what an input range is in terms of an interface, we can use it as a value typed vtable that yes can work in -betterC. Something like this should enable us to have better documentation using much simpler looking features without hiding away details in the source code.However my main concern with developing a new version of Phobos is isInputRange and friends will still exist. Unless the language has a better way of describing it e.g. signatures we may as well call it an incremental improvement not a new version.What's wrong with isInputRange? T
Oct 16 2019
On Wednesday, 16 October 2019 at 22:34:00 UTC, rikki cattermole wrote:/// Docs go here signature InputRange( named ElementType) { property { /// Docs go here ElementType front(); /// Docs go here bool empty(); } /// Docs go here void popFront(); } void func(T:InputRange)(T myInputRange) {}The experimental.typecons has an incomplete modification to wrap. It allows wrapping a structure into an interface if it conforms. If the edge cases were worked out then similar logic would be applicable to the function signature. ...) if(implements!(InputRange, R)) What would be nice from the language is the ability to print a message if no template matching occurs. Remember if it does not match it is just pulled from overload resolution.
Oct 16 2019
On 17/10/2019 1:36 PM, Jesse Phillips wrote:On Wednesday, 16 October 2019 at 22:34:00 UTC, rikki cattermole wrote:That works for matching an implementation to an interface. It does miss out on better error messages and any ability to let the interface override or extend the implementation (e.g. extraction of ElementType from front or using the declared type in body of the implementation). I.e. signature InputRange( named ElementType = ElementTypeCompat!(typeof(this)) { ... } Not to mention it forces what amounts to idiomatic D into a second class position in many use cases. Not preferable IMO./// Docs go here signature InputRange( named ElementType) { property { /// Docs go here ElementType front(); /// Docs go here bool empty(); } /// Docs go here void popFront(); } void func(T:InputRange)(T myInputRange) {}The experimental.typecons has an incomplete modification to wrap. It allows wrapping a structure into an interface if it conforms. If the edge cases were worked out then similar logic would be applicable to the function signature. ...) if(implements!(InputRange, R)) What would be nice from the language is the ability to print a message if no template matching occurs. Remember if it does not match it is just pulled from overload resolution.
Oct 16 2019
On Thursday, 17 October 2019 at 00:46:12 UTC, rikki cattermole wrote:I.e. signature InputRange( named ElementType = ElementTypeCompat!(typeof(this)) { ... } Not to mention it forces what amounts to idiomatic D into a second class position in many use cases. Not preferable IMO.auto foo(R, E = ElementType!R)() if(implements!(InputRange!E, R)) That seems pretty idiomatic D. Now as you said, it doesn't improve the error message. But what if the language changed so it could?
Oct 16 2019
On 17/10/2019 4:32 PM, Jesse Phillips wrote:On Thursday, 17 October 2019 at 00:46:12 UTC, rikki cattermole wrote:And that's the problem, for what is very common, it is absolutely horrible code.I.e. signature InputRange( named ElementType = ElementTypeCompat!(typeof(this)) { ... } Not to mention it forces what amounts to idiomatic D into a second class position in many use cases. Not preferable IMO.auto foo(R, E = ElementType!R)() if(implements!(InputRange!E, R)) That seems pretty idiomatic D.Now as you said, it doesn't improve the error message. But what if the language changed so it could?That would require flow analysis and it won't give good names to different aspects. We have done research into template constraints and to improve the error messages there. But aggregate checks like isInputRange and with that implements, the compiler can't understand it even with flow analysis sadly. Right now there is no way to communicate to the compiler the human aspects of a concept. Sure we can do the technical, but that only gets us so far (which we have been doing). This is what I am arguing for, a way to communicate to the compiler the human aspects of a concept. The behaviors and properties it must exhibit to match our mental model, not the compilers model.
Oct 16 2019
On Thursday, 17 October 2019 at 03:46:23 UTC, rikki cattermole wrote:On 17/10/2019 4:32 PM, Jesse Phillips wrote:I still think the only change that is needed is to make the operators return an error value instead of a boolean on failure. The error value then just needs to propagate properly through && and ||, and you should get an unambiguous error. You could even add further information with a wrapper template, as long as the error object is inspectable and rewritable. I don't think the right approach is to have the compiler automagically produce good error messages, but rather give the template developers tools to help the compiler inform the user what actually went wrong.Now as you said, it doesn't improve the error message. But what if the language changed so it could?That would require flow analysis and it won't give good names to different aspects. We have done research into template constraints and to improve the error messages there. But aggregate checks like isInputRange and with that implements, the compiler can't understand it even with flow analysis sadly.
Oct 17 2019
On Wednesday, 16 October 2019 at 22:34:00 UTC, rikki cattermole wrote:So these sorts of "functions" are aggregates of behavior and properties that require reading the source code to know fully what it entails. Yes, aggregates of behavior can be complex, and it does make sense to use "functions" to do it. But the key difference here is if you can describe what most of the behaviors and properties are to the compiler it can produce better error messages but also allow code to be more descriptive. I.e. /// Docs go here signature InputRange( named ElementType) { property { /// Docs go here ElementType front(); /// Docs go here bool empty(); } /// Docs go here void popFront(); } void func(T:InputRange)(T myInputRange) {} The above uses DIP1020 just to make this conversation a little easier to understand (ElementType will be inferred automatically from the implementation). And because we have described what an input range is in terms of an interface, we can use it as a value typed vtable that yes can work in -betterC. Something like this should enable us to have better documentation using much simpler looking features without hiding away details in the source code.Can't we just allow structs to implement interfaces and use template specialization? Something like this: interface InputRange(ElementType) { ElementType front(); bool empty(); void popFront(); } struct Range(E) : InputRange!E { E front() { return E.init; } bool empty() { return true; } void popFront() { } } void foo(T : InputRange!int)(T range) {} void bar() { InputRange!int a = Range!int.init; // will not compile } -- /Jacob Carlborg
Oct 17 2019
On 18/10/2019 12:48 AM, Jacob Carlborg wrote:Can't we just allow structs to implement interfaces and use template specialization? Something like this: interface InputRange(ElementType) { ElementType front(); bool empty(); void popFront(); } struct Range(E) : InputRange!E { E front() { return E.init; } bool empty() { return true; } void popFront() { } } void foo(T : InputRange!int)(T range) {} void bar() { InputRange!int a = Range!int.init; // will not compile } -- /Jacob CarlborgThat is a solution yes. The reason I do not believe it is one of the better ones is because the struct has to inherit from the interface (and fields are not supported). For reference Basile came up with this very solution over a year ago. The way we use input ranges today and with that DbI in general, is that the interface inherits from the implementation as part of the declaration of its usage. This is a very different approach to how we think of classes and much more inline with signatures from ML[0]. [0] https://www.cs.cmu.edu/~rwh/introsml/modules/sigstruct.htm
Oct 17 2019
On Wednesday, 16 October 2019 at 22:34:00 UTC, rikki cattermole wrote:On 17/10/2019 11:16 AM, H. S. Teoh wrote:https://github.com/atilaneves/concepts/blob/master/source/concepts/implements.d[...]So these sorts of "functions" are aggregates of behavior and properties that require reading the source code to know fully what it entails. [...]
Oct 17 2019
On Thursday, 17 October 2019 at 16:21:18 UTC, Atila Neves wrote:On Wednesday, 16 October 2019 at 22:34:00 UTC, rikki cattermole wrote:Correct me if I'm wrong, but would using this with std.range be as simple as: import std.range; implements!(MyCoolRange, InputRange) struct MyCoolRange(T) { .... } long sum(R)(R range) if (implements!(R, InputRange)) { .... }On 17/10/2019 11:16 AM, H. S. Teoh wrote:https://github.com/atilaneves/concepts/blob/master/source/concepts/implements.d[...]So these sorts of "functions" are aggregates of behavior and properties that require reading the source code to know fully what it entails. [...]
Oct 17 2019
On Thursday, 17 October 2019 at 19:37:38 UTC, Meta wrote:[snip] Correct me if I'm wrong, but would using this with std.range be as simple as: import std.range; implements!(MyCoolRange, InputRange) struct MyCoolRange(T) { .... } long sum(R)(R range) if (implements!(R, InputRange)) { .... }implements is for an interface. You would actually use models (with the isInputRange from the concepts library, not phobos), so change implements!(MyCoolRange, InputRange) to models!(MyCoolRange, isInputRange) and you don't need models for below, just change if (implements!(R, InputRange)) to if (isInputRange!R) but make sure you are using the one from the concepts library.
Oct 17 2019
On Thursday, 17 October 2019 at 20:50:54 UTC, jmh530 wrote:On Thursday, 17 October 2019 at 19:37:38 UTC, Meta wrote:I'm referring to the InputRange et al. interfaces from std.range.interfaces: https://dlang.org/phobos/std_range_interfaces.html[snip] Correct me if I'm wrong, but would using this with std.range be as simple as: import std.range; implements!(MyCoolRange, InputRange) struct MyCoolRange(T) { .... } long sum(R)(R range) if (implements!(R, InputRange)) { .... }implements is for an interface. You would actually use models (with the isInputRange from the concepts library, not phobos), so change implements!(MyCoolRange, InputRange) to models!(MyCoolRange, isInputRange) and you don't need models for below, just change if (implements!(R, InputRange)) to if (isInputRange!R) but make sure you are using the one from the concepts library.
Oct 17 2019
On Thursday, 17 October 2019 at 21:24:15 UTC, Meta wrote:[snip] I'm referring to the InputRange et al. interfaces from std.range.interfaces: https://dlang.org/phobos/std_range_interfaces.htmlOh sorry. I completely forgot that was in there.
Oct 17 2019
On 18/10/2019 8:37 AM, Meta wrote:On Thursday, 17 October 2019 at 16:21:18 UTC, Atila Neves wrote:This unfortunately still ties the implementation itself to the interface. Which goes against DbI.On Wednesday, 16 October 2019 at 22:34:00 UTC, rikki cattermole wrote:Correct me if I'm wrong, but would using this with std.range be as simple as: import std.range; implements!(MyCoolRange, InputRange) struct MyCoolRange(T) { .... } long sum(R)(R range) if (implements!(R, InputRange)) { .... }On 17/10/2019 11:16 AM, H. S. Teoh wrote:https://github.com/atilaneves/concepts/blob/master/source/c ncepts/implements.d[...]So these sorts of "functions" are aggregates of behavior and properties that require reading the source code to know fully what it entails. [...]
Oct 17 2019
On Friday, 18 October 2019 at 00:19:08 UTC, rikki cattermole wrote:Not necessarily. I haven't tried this myself, but I think you could get pretty far with UDAs and some template magic. What I'm thinking: //Unfortunately this is necessary so that R is in scope for the UDAs. //Maybe it can be avoided with std.traits.TemplateArgsOf / TemplateOf? template MapResult(R) { //MapResult is always at least an input range implements!(MapResult, InputRange) //If the wrapped type is a forward range, MapResult //is also a forward range and will forward to its implementation given!(implements!(R, ForwardRange), implements!(inheritImpl!(ForwardRange, MapResult, R), ForwardRange)) //etc. struct MapResult { R store; mixin forwardTo!(ForwardRange, store); //Input range primitives defined down here } }Correct me if I'm wrong, but would using this with std.range be as simple as: import std.range; implements!(MyCoolRange, InputRange) struct MyCoolRange(T) { .... } long sum(R)(R range) if (implements!(R, InputRange)) { .... }This unfortunately still ties the implementation itself to the interface. Which goes against DbI.
Oct 18 2019
On Friday, 18 October 2019 at 15:12:45 UTC, Meta wrote:Not necessarily. I haven't tried this myself, but I think you could get pretty far with UDAs and some template magic. What I'm thinking: [snip]I don't understand this line: given!(implements!(R, ForwardRange), implements!(inheritImpl!(ForwardRange, MapResult, R), ForwardRange)) I guess I still don't understand why you prefer the implements with interfaces rather than the concepts library's versions of isInputRange/isForwardRange/etc. What does this version add to the static if version (assuming phobos's isInputRange, etc., were replaced with the concepts version?
Oct 18 2019
On Friday, 18 October 2019 at 15:56:24 UTC, jmh530 wrote:On Friday, 18 October 2019 at 15:12:45 UTC, Meta wrote:I wrote that in response to Rikki's assertion: "This unfortunately still ties the implementation itself to the interface. Which goes against DbI." Just some spitballing on how DbI could harmoniously co-exist with Atila's concepts library.Not necessarily. I haven't tried this myself, but I think you could get pretty far with UDAs and some template magic. What I'm thinking: [snip]I don't understand this line: given!(implements!(R, ForwardRange), implements!(inheritImpl!(ForwardRange, MapResult, R), ForwardRange))I guess I still don't understand why you prefer the implements with interfaces rather than the concepts library's versions of isInputRange/isForwardRange/etc. What does this version add to the static if version (assuming phobos's isInputRange, etc., were replaced with the concepts version?I don't necessarily, but it's good to have options. I think it would be very nice if the concepts library were as easy as `import std.range.interfaces; implements(InputRange, MyCoolRangeType)`, because then the friction for using it is reduced down to almost 0. I also just like the cleanliness of separating the interface from the implementation, which isInputRange also allows, but not in as clean a manner.
Oct 18 2019
On Friday, 18 October 2019 at 16:14:26 UTC, Meta wrote:[snip] I wrote that in response to Rikki's assertion: "This unfortunately still ties the implementation itself to the interface. Which goes against DbI." Just some spitballing on how DbI could harmoniously co-exist with Atila's concepts library.I'm never quite sure whether I grok DbI or not...but all those static if's in phobos's MapResult are introspection to make sure that the range type has the appropriate functions and include the relevant text in MapResult. So it seems to me that isInputRange in phobos is DbI-compatible, particularly when re-reading what Rikki wrote. He seems to be arguing that what you are doing is not DbI because you are using interfaces instead. I think he would be making that complaint about any use of interfaces. However, the concepts library has more than just implements. Its alternative isInputRange could replace phobos's isInputRange or alternately be used used with the models template as needed. In my limited DbI understanding, that would be closer to DbI than what you are trying to do.
Oct 18 2019
On Friday, 18 October 2019 at 17:09:55 UTC, jmh530 wrote:On Friday, 18 October 2019 at 16:14:26 UTC, Meta wrote:Exactly, making it very hard to use implements from Atila's library, because MapResult may or may not implement the necessary primitives to be, say, a forward range, depending on whether the source range implements them. Yes, of course you can just use `isInputRange` instead, but we should aim to provide options, and I prefer the cleanliness of the former.[snip] I wrote that in response to Rikki's assertion: "This unfortunately still ties the implementation itself to the interface. Which goes against DbI." Just some spitballing on how DbI could harmoniously co-exist with Atila's concepts library.I'm never quite sure whether I grok DbI or not...but all those static if's in phobos's MapResult are introspection to make sure that the range type has the appropriate functions and include the relevant text in MapResult.So it seems to me that isInputRange in phobos is DbI-compatible, particularly when re-reading what Rikki wrote. He seems to be arguing that what you are doing is not DbI because you are using interfaces instead.I may be misunderstanding him, but I believe his main problem with using interfaces is that the struct conforms to the interface, but does not inherit its the behaviour (e.g., MapResult implements .save only if the underlying range does, and forwards to its implementation, which is not possible without extra boilerplate, were we to just allow structs to implement interfaces as a solution). Also, interfaces can't have non-immutable fields... and there's _not_ really any way around that, but at least in the concept of Phobos ranges, the API consists only of functions, not fields. My point was that we can do DbI using structs implementing interfaces, and I provided some strawman implementation to show how it might be done.However, the concepts library has more than just implements. Its alternative isInputRange could replace phobos's isInputRange or alternately be used used with the models template as needed.Sure, I'm not disputing that.In my limited DbI understanding, that would be closer to DbI than what you are trying to do.I disagree, my whole point being that DbI is still possible while also allowing structs to implement interfaces (which is basically what implements is), and maybe preferable in some cases.
Oct 18 2019
On 19/10/2019 7:35 AM, Meta wrote:On Friday, 18 October 2019 at 17:09:55 UTC, jmh530 wrote:So my problem is with the struct itself knowing about the "interface" (whatever definition you use doesn't matter). Currently we are good with isInputRange. Because the implementation of an input range does not need to know about that "function" in any form including the InputRange class interface. DbI works at the usage site, not at the declaration site of whatever is getting passed in. Its about limiting and adapting the user code to fit the types being passed in. So it doesn't matter if you inherit a class interface from a struct, or use a UDA, you are telling the type about the interface. I.e. auto map(Args)(Args arg) { static struct Map { property { Something front() nogc { ... } bool empty() nogc { ... } } void popFront() nogc { ... } } return Map(arg); } void myFunc(IR)(IR input) { ... } What we want to do, is restrict the template parameter (IR) to an input range. But the input range interface that is being used (e.g. a variant like nogc) may not have been known to the map function (doesn't matter why) and there is no reason for it to have known about it at all. There may also be other restricting factors like the ElementType. Now for very simple cases this can be done as part of a template parameter, and more complex ones can go into template constraints like we do now (since its a more advanced use case). Thing is, if all we want to do is to check if its an input range, we shouldn't need to use template constraints. They are a very advanced language feature involving CTFE and language based traits. So if we were to look into rewriting Phobos, shouldn't we make something that is common and fairly advanced, into something that is simple to understand? Because that is what I'm arguing for. Also: auto:InputRange map(Args)(Args arg) { .. } A function that returns a value whose type conforms to the InputRange specification. This would significantly improve the documentation (as it cannot be done right now and people have tried to find a solution).On Friday, 18 October 2019 at 16:14:26 UTC, Meta wrote:Exactly, making it very hard to use implements from Atila's library, because MapResult may or may not implement the necessary primitives to be, say, a forward range, depending on whether the source range implements them. Yes, of course you can just use `isInputRange` instead, but we should aim to provide options, and I prefer the cleanliness of the former.[snip] I wrote that in response to Rikki's assertion: "This unfortunately still ties the implementation itself to the interface. Which goes against DbI." Just some spitballing on how DbI could harmoniously co-exist with Atila's concepts library.I'm never quite sure whether I grok DbI or not...but all those static if's in phobos's MapResult are introspection to make sure that the range type has the appropriate functions and include the relevant text in MapResult.So it seems to me that isInputRange in phobos is DbI-compatible, particularly when re-reading what Rikki wrote. He seems to be arguing that what you are doing is not DbI because you are using interfaces instead.I may be misunderstanding him, but I believe his main problem with using interfaces is that the struct conforms to the interface, but does not inherit its the behaviour (e.g., MapResult implements .save only if the underlying range does, and forwards to its implementation, which is not possible without extra boilerplate, were we to just allow structs to implement interfaces as a solution).
Oct 18 2019
On Saturday, 19 October 2019 at 02:57:33 UTC, rikki cattermole wrote:auto:InputRange map(Args)(Args arg) { .. } A function that returns a value whose type conforms to the InputRange specification. This would significantly improve the documentation (as it cannot be done right now and people have tried to find a solution).auto map(Args...)(Args arg) out (result; isInputRange!(typeof(result))) do { ... }
Oct 19 2019
On 20/10/2019 2:45 AM, Paul Backus wrote:On Saturday, 19 October 2019 at 02:57:33 UTC, rikki cattermole wrote:I am unsure how to respond to this. Yes it works right now. But that amount of syntax and the semantics that go along with it, does not inspire "ease of use" or "easy to understand" in me.auto:InputRange map(Args)(Args arg) { .. } A function that returns a value whose type conforms to the InputRange specification. This would significantly improve the documentation (as it cannot be done right now and people have tried to find a solution).auto map(Args...)(Args arg) out (result; isInputRange!(typeof(result))) do { ... }
Oct 19 2019
On Sunday, 20 October 2019 at 00:46:54 UTC, rikki cattermole wrote:On 20/10/2019 2:45 AM, Paul Backus wrote:I agree that it's a bit ugly. The main advantage is that it's part of the function's signature, so it's guaranteed to show up in the documentation.auto map(Args...)(Args arg) out (result; isInputRange!(typeof(result))) do { ... }I am unsure how to respond to this. Yes it works right now. But that amount of syntax and the semantics that go along with it, does not inspire "ease of use" or "easy to understand" in me.
Oct 19 2019
On Saturday, 19 October 2019 at 02:57:33 UTC, rikki cattermole wrote:So my problem is with the struct itself knowing about the "interface" (whatever definition you use doesn't matter). Currently we are good with isInputRange. Because the implementation of an input range does not need to know about that "function" in any form including the InputRange class interface. DbI works at the usage site, not at the declaration site of whatever is getting passed in. Its about limiting and adapting the user code to fit the types being passed in. So it doesn't matter if you inherit a class interface from a struct, or use a UDA, you are telling the type about the interface. I.e. auto map(Args)(Args arg) { static struct Map { property { Something front() nogc { ... } bool empty() nogc { ... } } void popFront() nogc { ... } } return Map(arg); } void myFunc(IR)(IR input) { ... } What we want to do, is restrict the template parameter (IR) to an input range. But the input range interface that is being used (e.g. a variant like nogc) may not have been known to the map function (doesn't matter why) and there is no reason for it to have known about it at all.I assume you're describing ML's signatures, which I'm not familiar with, but I see your problem with structs implementing interfaces. However, I don't see how `implements` has this same problem. It's all ad hoc; the "implementing" struct never has to know that the InputRange interface exists at all.There may also be other restricting factors like the ElementType. Now for very simple cases this can be done as part of a template parameter, and more complex ones can go into template constraints like we do now (since its a more advanced use case). Thing is, if all we want to do is to check if its an input range, we shouldn't need to use template constraints. They are a very advanced language feature involving CTFE and language based traits. So if we were to look into rewriting Phobos, shouldn't we make something that is common and fairly advanced, into something that is simple to understand? Because that is what I'm arguing for.I agree, but the only comparable language that tried to solve this problem is C++, and they ended up with a real monster of a feature. Rust has `impl <trait>`, but it has the same problem as interfaces in that it's not ad hoc.Also: auto:InputRange map(Args)(Args arg) { .. } A function that returns a value whose type conforms to the InputRange specification. This would significantly improve the documentation (as it cannot be done right now and people have tried to find a solution).Yes, I agree that's a major weakness both for template constraints and Atila's concepts library.
Oct 19 2019
On 20/10/2019 2:32 PM, Meta wrote:Swift and Rust can be lumped together (trait + protocols) which I believe are loosely based upon ML's signatures. Except that you need to have a separate implementation type to join the interface to the original type. In D we don't need to have the secondary implementation to join the two together because of our meta-programming capabilities along with CTFE. Here is the best resource for it we have managed to come up with on Discord: https://www.cs.cmu.edu/~rwh/introsml/modules/sigstruct.htm While we can take inspiration from other languages I do think that we are mostly on our own with this. Our idioms and usage of them are different enough that we can't just copy other programming languages designs for language features for what we are already doing poorly in library.There may also be other restricting factors like the ElementType. Now for very simple cases this can be done as part of a template parameter, and more complex ones can go into template constraints like we do now (since its a more advanced use case). Thing is, if all we want to do is to check if its an input range, we shouldn't need to use template constraints. They are a very advanced language feature involving CTFE and language based traits. So if we were to look into rewriting Phobos, shouldn't we make something that is common and fairly advanced, into something that is simple to understand? Because that is what I'm arguing for.I agree, but the only comparable language that tried to solve this problem is C++, and they ended up with a real monster of a feature. Rust has `impl <trait>`, but it has the same problem as interfaces in that it's not ad hoc.
Oct 19 2019
On Wednesday, 16 October 2019 at 17:20:28 UTC, berni44 wrote:In the feedback thread H. S. Teoh is talking about that we need a new/better version of Phobos. I remember having read the same in a comment on some PR recently. How would this better version look like? Is there allready any picture of what we do want? One says, if you don't know the goal, all paths are the wrong ones... A few things that I remember from various sources: * Some improvement in the realm of ranges. * Replacement of some old modules. (std.xml, std.outbuffer, std.socket, what else?) * Adding some missing modules (std.eventloop, std.database, what else?) * Unifying some modules (everything covering selfinspection, like std.traits and so on, whar else?) Anything more?I'd like Phobos to be something like Go's stdlib in a sence that a lot of the stuff needed for day to day programming would be builtin. Crypto stuff, compression stuff, https stuff and etc.
Oct 17 2019
On Wednesday, 16 October 2019 at 17:20:28 UTC, berni44 wrote:How would this better version look like?I hoped to be able to summarize all the things, that you wrote, but effectivly there is only little, that came up. Thanks anyway to all of you who answered. From my point of few there are two quite different things to do: a) Adding, removing and combining modules. That's something, that should be doable, partly by using deprecation, partly even without. This could be called "incremental improvement". b) Correcting design mistakes made in the past. This sounds much more difficult, especially when it affects stuff, that is used quite often, like strings and ranges. And there is the fear, that this might bring down D alltogether. This would probably need a "new version".
Oct 20 2019
On 21/10/2019 2:37 AM, berni44 wrote:b) Correcting design mistakes made in the past. This sounds much more difficult, especially when it affects stuff, that is used quite often, like strings and ranges. And there is the fear, that this might bring down D alltogether. This would probably need a "new version".I wouldn't worry about it, we can do it incrementally and limit breakage. And we can always split out any module that is being removed we have done it before i.e. std.streams
Oct 20 2019