Undo in D
Is there any idiomatic undo designs in D that give a more natural implementation than the standard techniques?
Re: typeof on protected field
On Sunday, 17 June 2018 at 02:29:12 UTC, Adam D. Ruppe wrote: On Saturday, 16 June 2018 at 08:32:38 UTC, DigitalDesigns wrote: I need to get the protected and private members for serialization. This breaks encapsulation. A better design would be to have a class know how to serialize itself via a serializable interface. Yeah, but that is a lot of extra work when it is generally unnecessary and breaks encapsulation far more than a CT reflection based scheme. CT reflection should not have these same restrictions and encapsulation does not technically apply. Encapsulation cannot reflect in a generic way. Reflection can be generic and hence handle any case. OOP and Reflection are two different things and encapsulation is mainly for OOP. After all, encapsulation is optional and one can code so things are highly dependent... so why should reflection break in one case but not the other? One can easily deal with encapsulation in reflection if they desire but it shouldn't be forced as it take away many useful possibilities. With proper CT reflection one does not have to touch any code and it can just work. With oop one has to modify the classes to support serialization. That's a huge difference.
Re: How do you test whether a variable is static or not?
On Saturday, 16 June 2018 at 21:41:37 UTC, Jonathan M Davis wrote: On Saturday, June 16, 2018 14:55:51 Steven Schveighoffer via Digitalmars-d- learn wrote: On 7/30/16 8:47 AM, Jonathan M Davis via Digitalmars-d-learn wrote: > I'm writing some serialization code where I need to skip > static variables. So, I have a symbol from a struct, and I'd > like to test whether it's static or not. Ideally, I'd be > able to do something like > > is(field == static) std.traits.hasStaticMember ? https://dlang.org/phobos/std_traits.html#hasStaticMember Yeah. I wrote that, and it got added to Phobos. If you'll note, my post in this thread was from almost two years ago. - Jonathan M Davis doesn't work: ..\..\src\phobos\std\traits.d(3823): Error: class `app.A` member `z` is not accessible. What is the point of introspection if one can't get information about a type due to it's protection level? For example, how is one suppose to serialize a class that has protected and private members, which are common, when using properties?
Re: How do you test whether a variable is static or not?
On Saturday, 30 July 2016 at 13:04:56 UTC, Ali Çehreli wrote: On 07/30/2016 05:47 AM, Jonathan M Davis via Digitalmars-d-learn wrote: > I'm writing some serialization code where I need to skip static variables. > So, I have a symbol from a struct, and I'd like to test whether it's static > or not. static variables don't have the .offsetof property: struct S { int a; static int b; } // Bonus question: should field be alias or string? template isStaticVar(T, alias field) { enum isStaticVar = !__traits(compiles, mixin("T." ~ field ~ ".offsetof")); } void main() { static assert (!isStaticVar!(S, "a")); static assert (isStaticVar!(S, "b")); } Ali This doesn't work, treats fields in base classes as static. One way to test if a member is static is if it it doesn't exist in tupleof... but this only returns the immediate members and so will fail. I guess one will have to check all base types too and if it doesn't exist in any of then it should be static. Why is it so hard to be able to get basic information like if a type is static or not?
typeof on protected field
mixin(`foo!(typeof(T.`~m~`)); gives me an error about m being protected. Error: class `X` member `name` is not accessible. this also happens when using __traits(getMember, T, m); X is in another module. Works fine when X is in the same module. I need to get the protected and private members for serialization.
Re: Get static fields!
On Saturday, 16 June 2018 at 07:56:22 UTC, Bauss wrote: On Saturday, 16 June 2018 at 05:05:19 UTC, DigitalDesigns wrote: tupleof does not return static fields as does not Fields. Currently the only method seems to be use allMembers, but that returns members requiring filtering, which there is no good filtering checks. I'd simply like to get all the fields of a type, static and non-static. What about derivedMembers? But I don't want derived members!
Get static fields!
tupleof does not return static fields as does not Fields. Currently the only method seems to be use allMembers, but that returns members requiring filtering, which there is no good filtering checks. I'd simply like to get all the fields of a type, static and non-static.
Storing temp for later use with ranges
Does ranges have the ability to store a temp value in a "range like way" that can be used later? The idea is to avoid having to create temp variables. A sort of range with "memory"
returning to thrown
I have to modify preexisting code. As of now, the code fails and throws an exception at some point. I need to prevent the code from throwing(easy) but signal to the user of the code some notification(hard). It would be cool if I could throw an exception as if the code yielded and it could be continued if I want. simplified pseudoscope void load() { read(somefile); <-- throws if somefile does not exist ... } goes in to void load() { try { file = read(somefile); <-- throws if somefile does not exist } catch { file = null; throw new yeildException!4("File not found!"); } yieldException!4: ... } then when one catches a yieldException somehow they can resume at the proper location to continue the function as if the exception never happened. Because I don't have access to all the code nor do I want to rewrite large portions of it, it is impossible to redesign everything to make things work correctly. I believe throw unwinds the stack which makes a yield semantic impossible? I can't use a callback(too ugly and it would require modify huge amounts of code to add them everywhere unless it were global): void load() { try { file = read(somefile); <-- throws if somefile does not exist } catch { file = null; userCallback("File not found!"); } ... } Any devious D tricks that can be used to give the sort of yieldThrow I'm looking for? BTW, if D had a yieldThrow which behaved like throw but saved the stack to rewind back to the point of yieldThrow, then one could simply do void load() { try { file = read(somefile); <-- throws if somefile does not exist } catch { yieldThrow new yeildException!4("File not found!"); // code returned back to this point when yieldThrow finished doing what it does. file = null; } ... } Remember, these errors occur inside some large processing(of a file) which might error depending on dependencies. Some of these errors are not critical and I can't reparse the file each time because the same error will occur. I simply need to ignore the errors. I have access to the code where I can ignore them but I need some nice way to inform the user of the process that something didn't go as planed. Again, this wasn't defined in to the original code and it it already has it's own error handling.
Re: Orange check failling all of a sudden
Also, is there any way to have a field as optional? Right now when I update a filed in a serialized type the app crashes because it can't find the field in the serialized data(since it was just added in the code). This requires either regenerating the data or manually adding the serialized field to each entry... both are impractical. It would be nice to disable missing fields from throwing. While I could catch one error it would be a pain to try and catch an arbitrary number of them. Maybe an attribute is better used: @allowDefaultSerialized
Re: Orange check failling all of a sudden
I also get a lot of inout's attached to key names. Seems excessive but inout(inout(double)[]) /> Maybe they are necessary but seems like they are redundant.
Orange check failling all of a sudden
Changed some things in my app but unrelated to serialization and now my app fails when trying to read the xml that was generated at the output of the previous run. Where it is failing is here: void checkSpace(ref string s) @safe pure // rule 3 { import std.algorithm.searching : countUntil; import std.ascii : isWhite; import std.utf : byCodeUnit; mixin Check!("Whitespace"); ptrdiff_t i = s.byCodeUnit.countUntil!(a => !isWhite(a)); if (i == -1 && s.length > 0 && isWhite(s[0])) s = s[$ .. $]; else if (i > -1) s = s[i .. $]; if (s is old) fail(); } s = ="1.0" encoding="UTF-8"?> Actual xml data(first 3 lines): It seems odd that it should fail when munching whitespace. It seems that the checker is getting off to a bad start from the get go. - [orange.xml.PhobosXml.CheckException] 0x03135880 {err=0x, tail="="1.0" encoding="UTF-8"?> orange.xml.PhobosXml.CheckException + orange.xml.PhobosXml.XMLException 0x03135880 {} orange.xml.PhobosXml.XMLException err 0x orange.xml.PhobosXml.CheckException + tail"="1.0" encoding="UTF-8"?> ... const(char)[] + msg "Whitespace" const(char)[] line0 uint column 0 uint This was all working fine before and I'm not sure how it broke. The xmllint shows the xml is well formed so this is buggy code. Note that if I also remove all the xml inside data then the same error occurs, so this is my xml: that still fails when checking whitespace.
Re: Orange check failling all of a sudden
and if I completely remove the check then everything works fine. */ class DocumentParser : ElementParser { string xmlText; /** * Constructs a DocumentParser. * * The input to this function MUST be valid XML. * This is enforced by the function's in contract. * * Params: * xmlText_ = the entire XML document as text * */ this(string xmlText_) in { assert(xmlText_.length != 0); try { // Confirm that the input is valid XML //check(xmlText_); // COMMENTED OUT! } catch (CheckException e) { // And if it's not, tell the user why not assert(false, "\n" ~ e.toString()); }
Re: WTF! new in class is static?!?!
On Thursday, 7 June 2018 at 23:08:22 UTC, Steven Schveighoffer wrote: On 6/7/18 6:58 PM, DigitalDesigns wrote: On Thursday, 7 June 2018 at 21:57:17 UTC, Steven Schveighoffer wrote: On 6/7/18 5:07 PM, DigitalDesigns wrote: class A; class B { A a = new A(); } auto b1 = new B(); auto b2 = new B(); assert(b1.a == b2.a)!! Yep, long-standing issue: https://issues.dlang.org/show_bug.cgi?id=2947 Almost a decade old! wait! everyone is saying it is a feature! So, which is it, a feature or a bug?!?!? It's a feature that you can assign a static initializer to a class or struct member and have that work at compile time (using CTFE). But when it's a reference to mutable data, it's a bug. Just the idea that you have implicitly shared data if you create instances in multiple threads should make it obviously a bug. Even back then it was a debate, look at the bug report. But it's definitely a bug. Just hard to close since it will probably break a lot of code. -Steve I would expect that using a static initialize would not break as much code going from immutable to mutable than the other way around. Someone should have been smart enough to create a static new so both methods could have been implemented in a sane way.
Re: WTF! new in class is static?!?!
On Thursday, 7 June 2018 at 21:57:17 UTC, Steven Schveighoffer wrote: On 6/7/18 5:07 PM, DigitalDesigns wrote: class A; class B { A a = new A(); } auto b1 = new B(); auto b2 = new B(); assert(b1.a == b2.a)!! Yep, long-standing issue: https://issues.dlang.org/show_bug.cgi?id=2947 Almost a decade old! -Steve wait! everyone is saying it is a feature! So, which is it, a feature or a bug?!?!?
WTF! new in class is static?!?!
class A; class B { A a = new A(); } auto b1 = new B(); auto b2 = new B(); assert(b1.a == b2.a)!! I'm glad I finally found this out! This is not typical behavior in most languages is it? I'd expect it to be translated to something like class B { A a; this() { a = new A(); } } In C# it is different, can't remember if it is different in C++. This has caused bugs in my code because the fields are all pointing to the same data when I expected them to each have unique data ;/ This method is error prone and the behavior should be reversed, it should not break the majority of code. If one wants the current behavior then static new could be used or something else.
Re: New programming paradigm
On Sunday, 3 June 2018 at 16:36:52 UTC, Simen Kjærås wrote: On Sunday, 3 June 2018 at 14:57:37 UTC, DigitalDesigns wrote: On Sunday, 3 June 2018 at 09:52:01 UTC, Malte wrote: You might want to have a look at https://wiki.dlang.org/Dynamic_typing This sounds very similar to what you are doing. I never really looked into it, because I prefer to know which type is used and give me errors if I try to do stupid things, but I think it's a cool idea. No, this is not what I'm talking about, although maybe it could be related in some way. Actually, it sort of is. Your mapEnum is essentially the same as std.variant.visit (https://dlang.org/phobos/std_variant#.visit), and std.variant.Algebraic is the type that encapsulates both the runtime tag and the void[] containing the data of unknown type. Now, there may be many important differences - Algebraic encapsulates the data and tag, which may or may not be what you want, visit only takes one algebraic argument, mapEnum may be faster, more or less generic, etc. The idea of converting a run-time value to a compile-time value is the same, though. -- Simen I didn't know that variants had those functions! pretty nice. Yes, it is similar to what I'm doing. Same principles but just a little different perspective. I use enums, UDA's, and templates rather than a Algebraic and delegates. The difference is that the enum stores only the type information rather than the variable and the type info that Algebraic stores. If I were to have know about this before I might have used it instead and everything would have probably been fine. The only thing is that the enum version lets me store the type info separately than with the data. When several variables depend on the type id I think it will make it a little easier than having to manage several Algebraic type info's across several variables to sync them. For example dataType type; void[] in, out; rather than Algebraic!(type1,..., typen) in, out; and then having to make sure the types are synced between in and out. At least in my case it might be a little easier. Also my way uses a templated function directly rather than an array of lambads, although they are equivalent: Algebraic!(string, int) variant; variant.visit!((string s) => cast(int) s.length, (int i)=> i)(); which could be written as variant.visit!((string s) => foo(s), (int i)=> foo(i))(); auto foo(T)(T t) { } would become enum variant { @("int") _int, @("string") _string, } mixin(variant.MapEnum!("foo")()); auto foo(T)(T t) { } So, they definitely are very similar and actually might be identical. I haven't used Algebraic and visit any to know. What I do know is that for several Algebraics you would have to do something like variant.visit!((string s) => variant2.visit!((double d) => { foo(s,d); })), (int i)=> foo(i))(); etc. Which is creating the nested switch structure and can become complicated while my method still remains one line but foo just takes more than one template parameter. My feeling is mine is a little less robust since it's more for specific types of code while visit is a little more general. Mainly because of the hard coding of the mixin structure.
pipeProcess failing
I'm calling pipe process using pipeProcess([AliasSeq!args], Redirect.stdout | Redirect.stdin); where args is a tuple. Everything works when I pass each argument individually. If I combine any args using a space it fails or if I pass an argument with "". So I guess something like this pipeProcess(["dmd", "", "-m32 -JC:\"], Redirect.stdout | Redirect.stdin); will fail while pipeProcess(["dmd", "-m32", "-JC:\"], Redirect.stdout | Redirect.stdin); works. Is this a bug or something else going on I'm not aware of? I'm just wrapping pipe process in a function foo(Args...)(Args args) and calling it like foo("dmd", "", "-m32 -JC:\"). The reason why it is a problem is that it will simplify some code to be able to combine some arguments.
Re: New programming paradigm
On Sunday, 3 June 2018 at 09:52:01 UTC, Malte wrote: On Saturday, 2 June 2018 at 23:12:46 UTC, DigitalDesigns wrote: On Thursday, 7 September 2017 at 22:53:31 UTC, Biotronic wrote: [...] I use something similar where I use structs behaving like enums. Each field in the struct is an "enum value" which an attribute, this is because I have not had luck with using attributes on enum values directly and that structs allow enums with a bit more power. [...] You might want to have a look at https://wiki.dlang.org/Dynamic_typing This sounds very similar to what you are doing. I never really looked into it, because I prefer to know which type is used and give me errors if I try to do stupid things, but I think it's a cool idea. No, this is not what I'm talking about, although maybe it could be related in some way. What I am talking about is hooking up a runtime variable that can take a few values, such as from an enum and have those be mapped to a compile time template value. This way you get full static time checking of runtime code. Seems impossible? It's not! What it does is leverage D's meta programming engine to deal with all the routine possiblities. A large switch statement is what makes the runtime to compile time magic happen int x; switch(x) { default: foo!void(); case 0: foo!int(); case 1: foo!double(); etc... } See how the switch maps a runtime value x to a templated function foo? we then can handle the x values with foo void foo(T)() { // if x = 0 then T = int // if x = 1 then T = double } But inside foo we have T, the template variable that is the compile time representation of the dynamic variable x. Remember, x's value is unknown at compile time... the switch is what maps the runtime to the compile time. But in foo, because we have T, the type system all works fine. What makes this very useful that we can call templated functions using T and the meta engine will pick the right template function specialization. e.g., void bar(S)() { } can be used inside foo by calling bar!T(). It doesn't seem like much here if you had to use x it would be a pain. Either you would have to manually create switches or create a rats nest of if statements. But we never have to worry about that stuff when using the above method because it is exactly like programming at compile time as if x a compile time value(like say, just int). It works great when you have several template variables and just want everything to work together without having to go in to much trouble: foo(A,B)() { B b = 4; bar!(A)(b) } suppose A can come from int, double, and B from float and long That is 4 different combinations one would normally have to represent. Not a big deal until you have to handle every combination. Suppose you are working with void arrays. They contain types but you don't know the type except after compile time. Without using this technique you have to use casts and tricks and you'll find out if you screwed up some typing stuff at runtime. Using this technique you will not have a void array but a T[] with T being any of the possible types that you specify using UDA's. if you could if (x == 0) { foo(cast(int[])a); } else if (x == 1) { foo(cast(double[])a); } else but I can do that with one line which simply generates the switch for me. Really all I'm doing is hiding the switch so it all looks like some magic is happening in one line. But the fact that it becomes really simple to do seems to open up the use of it and conceptually on can then think of "x" as a compile time variable that can take on several possibilities.
Re: New programming paradigm
On Thursday, 7 September 2017 at 22:53:31 UTC, Biotronic wrote: On Thursday, 7 September 2017 at 16:55:02 UTC, EntangledQuanta wrote: Sorry, I think you missed the point completely... or I didn't explain things very well. I don't think I did - your new explanation didn't change my understanding at least. This indicates I'm the one who's bad at explaining. Ah well. The point of my post was mostly to rewrite the code you'd posted in a form that I (and, I hope, others) found easier to understand. I see no where in your code where you have a variant like type. True. I've now rewritten it to use std.variant.Algebraic with these semantics: auto foo(T1, T2)(T1 a, T2 b, int n) { import std.conv; return T1.stringof~": "~to!string(a)~" - "~T2.stringof~": "~to!string(b); } unittest { import std.variant; Algebraic!(float, int) a = 4f; Algebraic!(double, byte) b = 1.23; auto res = varCall!foo(a, b, 3); assert(res == "float: 4 - double: 1.23"); } template varCall(alias fn) { import std.variant; auto varCall(int n = 0, Args...)(Args args) { static if (n == Args.length) { return fn(args); } else { auto arg = args[n]; static if (is(typeof(arg) == VariantN!U, U...)) { foreach (T; arg.AllowedTypes) { if (arg.type == typeid(T)) return varCall!(n+1)(args[0..n], arg.get!T, args[n+1..$]); } assert(false); } else { return varCall!(n+1)(args); } } } } Sadly, by using std.variant, I've given up on the elegant switch/case in exchange for a linear search by typeid. This can be fixed, but requires changes in std.variant. Of course, it would be possible to hide all this behind compiler magic. Is that desirable? I frankly do not think so. We should be wary of adding too much magic to the compiler - it complicates the language and its implementation. This is little more than an optimization, and while a compiler solution would be less intrusive and perhaps more elegant, I do not feel it provides enough added value to warrant its inclusion. Next, I'm curious about this code: void bar(var t) { writeln("\tbar: Type = ", t.type, ", Value = ", t); } void main() { bar(3); // calls bar as if bar was `void bar(int)` bar(3.4f); // calls bar as if bar was `void bar(float)` bar("sad"); // calls bar as if bar was `void bar(string)` } What does 'var' add here, that regular templates do not? (serious question, I'm not trying to shoot down your idea, only to better understand it) One possible problem with var here (if I understand it correctly) would be separate compilation - a generated switch would need to know about types in other source files that may not be available at the time it is compiled. Next: var foo(var x) { if (x == 3) return x; return "error!"; } This looks like a sort of reverse alias this, which I've argued for on many occasions. Currently, it is impossible to implement a type var as in that function - the conversion from string to var would fail. A means of implementing this has been discussed since at least 2007, and I wrote a DIP[1] about it way back in 2013. It would make working with variants and many other types much more pleasant. [1]: https://wiki.dlang.org/DIP52 I use something similar where I use structs behaving like enums. Each field in the struct is an "enum value" which an attribute, this is because I have not had luck with using attributes on enum values directly and that structs allow enums with a bit more power. When a runtime value depends on these structs one can build a mapping between the values and functional aspects of program. Since D has a nice type system, one can provide one templated function that represents code for all the enum values. E.g., enum TypeID // actually done with a struct { @("int") i, @("float") f } struct someType { TypeID id; } someType.id is runtime dependent. But we want to map behavior for each type. if (s.id == TypeID.i) fooInt(); if (s.id == TypeID.f) fooFloat(); For lots of values this is tedius and requires N functions. Turning foo in to a template and autogenerating the mapping using mixins we can get something like mixin(MapEnum!(TypeID, "foo")(s.id)) which generates the following code: switch(s.id) { case TypeID.i: foo!int(); break; case TypeID.f: foo!float(); break; } and of course we must create foo: void foo(T)() { } but rather than one for each enum member, we just have to have one. For certain types of code, this works wonders. We can treat runtime dependent values as if they were compile time values without too much work. MapEnum maps runtime to compile time behavior allowing us to use use templates to handle runtime variables. T in foo is actually acting in a runtime fashion depending on the value of id.
Re: Setter chaining
The above idea can be emulated in code, abiet ugly and useless: https://dpaste.dzfl.pl/bd118bc1910c import std.stdio; struct CT(A,B) { A v; B t; alias v this; B opUnary(string s)() if (s == "~") { return t; } A opUnary(string s)() if (s == "*") { return v; } } class C { int q; CT!(int, typeof(this)) foo() { q = 3; CT!(int, typeof(this)) v; v.t = this; v.v = q; return v; } CT!(int, typeof(this)) bar(int y) { q = q + y; CT!(int, typeof(this)) v; v.t = this; v.v = q; return v; } } void main() { C c = new C(); auto x = *((~c.foo()).bar(6)); writeln(x); } With a language implementation, all one would need is a symbol, using #, everything would simplify to class C { int q; int foo() { q = 3; return q; } int bar(int y) { q = q + y; return q;} } auto x = c.#foo().bar(6);
Re: Setter chaining
On Wednesday, 30 May 2018 at 15:46:36 UTC, Steven Schveighoffer wrote: On 5/30/18 10:49 AM, DigitalDesigns wrote: Does it sound good? class X { double x; @property X foo(double y) { x = y; return this; } @property X bar(double y) { x = y + 5; return this; } } void main() { X x = new X(); x.foo(3).bar(4); } It sort of emulates UFCS but I'm not sure if it's more trouble than it's worth. I figure it would be better than just returning void as it provides the option to chain but not sure if it will come back to bite me. Yes, I do this kind of stuff, but you need to word your functions correctly. I would avoid @property there, as this implies you should use it like: x.foo = 5; and if you return a reference to the type itself, it will read weird if you do it that way: auto five = (x.foo = 5); Here the name of the function is really really important. In my use case, I am kind of using it in an SQL builder type, where each time you call a method it adds some piece of the query. Like: auto query = table.select("id, name").where("foo = 5").orderBy("name"); -Steve Well, what I mean is to be able to have the ability to assign like a field or a function. sometimes I might want to use it as a property like x.foo = 5; and sometimes like a method x.foo(5).foo(8); for chaining. Rather than having to to create setfoo and such. Since D allows both syntaxes to be used, rather than returning void, turning parenting object allows the chaining to take place. Since the trick here is to be consistent, all setters must follow this principle, it shouldn't be a problem with consistency. auto five = (x.foo = 5); I wouldn't do that,just doesn't look right but I see your point. What would be cool is if D had some special way to return the object of the class the setter was in. auto x = (@x.foo = 5); Here @ returns x but first computes x.foo = 5;. In a way, it is like "this". @ gets the "this" of the function. Could work on any function: class Y { void foo(); @property int baz(); @property double bar(int x); } y.@foo() returns y; y.@baz() returns y; y.@bar(3) returns y; Essentially one could few all functions as returning this and the value in a tuple and be default the value is returned and using a "selector" character will return this. class Y { Tuple!(void, typeof(this)) foo(); Tuple!(int, typeof(this)) baz(); Tuple!(double, typeof(this)) bar(int x); } y.foo()[1] returns y; ... The compiler could simplify all this and by putting this in a register it could be be quite fast. In fact, since these are member functions and this is passed it will just fall through so very little overhead. The compiler can also optimize the code. Might take a bit to verify all the corner cases but would probably be useful once people could use it and get used to it. @, $, |, ?, ! or many symbols could be used without ambiguity because a dot will always preceded them.
Setter chaining
Does it sound good? class X { double x; @property X foo(double y) { x = y; return this; } @property X bar(double y) { x = y + 5; return this; } } void main() { X x = new X(); x.foo(3).bar(4); } It sort of emulates UFCS but I'm not sure if it's more trouble than it's worth. I figure it would be better than just returning void as it provides the option to chain but not sure if it will come back to bite me.
Re: Build interface from abstract class
On Wednesday, 30 May 2018 at 10:31:27 UTC, Simen Kjærås wrote: On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote: I do not think this is a problem in D. Infinite recursion can always be terminated with appropriate means. 1. Use attributes. methods in class A should be marked as being for the interface. When added to the interface they will not have the attribute so will not be picked up again. 2. Your method of function creation does not pick up attributes and other factors so it is weak. Here is my solution that does not solve problem 2: [Neat stuff] Neat, but as you say it doesn't handle attributes or UDAs. The use of stringof is also a red flag - the same name can apply to different types in different scopes, and aliases may confuse it. Here's a version that solves both of those issues: import std.array : join; import std.meta : ApplyLeft, staticMap, Filter, Alias; import std.traits; enum isPublic(alias overload) = Alias!(__traits(getProtection, overload) == "public"); interface InterfaceFromClass(T, alias filter = isPublic) { static foreach (overload; Filter!(filter, staticMap!(ApplyLeft!(MemberFunctionsTuple, T), __traits(derivedMembers, T mixin("@(__traits(getAttributes, overload)) "~attributes!overload~" ReturnType!overload "~__traits(identifier, overload)~"(Parameters!overload);"); } string attributes(alias overload)() { enum attrs = Filter!(ApplyLeft!(hasFunctionAttributes, overload), "pure", "nothrow", "ref", "@property", "@trusted", "@safe", "@nogc", "@system", "const", "immutable", "inout", "shared", "return", "scope"); return [attrs].join(" "); } alias A = InterfaceFromClass!C; abstract class C : A { int n; @("InterfaceMembers") { @(3) ref int foo(ref int a) { return n; } @(19) @safe void bar() { } } } // https://issues.dlang.org/show_bug.cgi?id=18915 // class D : C {} static assert([__traits(allMembers, A)] == ["foo", "bar"]); static assert(functionAttributes!(A.foo) == functionAttributes!(C.foo)); static assert(functionAttributes!(A.bar) == functionAttributes!(C.bar)); static assert(is(Parameters!(A.foo) == Parameters!(C.foo))); static assert(is(Parameters!(A.bar) == Parameters!(C.bar))); Note the link to issue 18915 (that's your 'string mixin output works...' post). I believe if we can fix that, the above should work. -- Simen Yeah! with a little work you can include fields in the interfacemembers because they will be ignored. I see no reason to have to declare an interface in D except in rare occasions! One should be able to abstract out an interface from a class or abstract class and use it as the base only for others to use. If a program was "sealed" there would be no real point in using interfaces(assuming it was designed to perfection) except to get around the diamond problem, which is what interfaces solve but in the process have forced us to duplicate code. The above technique alleviates that problem greatly. It's still bring the members inside the interface because it allows one to add final, static, and normal members if desired, although, this can be done by using another interface and inheriting from that.
Re: Build interface from abstract class
On Wednesday, 30 May 2018 at 01:46:30 UTC, Chameleon wrote: On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote: Here is my solution that does not solve problem 2: import std.stdio; [...] this is not programming. this is witchcraft! Just call me Dandalf the D Slayer! At least I finally got it to work. It's terrible that I have to use import and read the file in directly to do this ;/ It is working though.
Re: Build interface from abstract class
On Tuesday, 29 May 2018 at 20:53:14 UTC, DigitalDesigns wrote: On Tuesday, 29 May 2018 at 20:26:52 UTC, arturg wrote: On Tuesday, 29 May 2018 at 19:06:24 UTC, DigitalDesigns wrote: On Monday, 28 May 2018 at 22:15:40 UTC, arturg wrote: this might help you, https://dpaste.dzfl.pl/2cf844a11e3f you can use them to generate the functions as strings. Thanks, So, the problem I'm having is that I cannot use the generated interface for the abstract class because the abstract class needs the interface defined. I need to be able to forward define the interface then extend it. D doesn't like this main.d(10): Error: interface `main.B` base `A` is forward referenced interface A; mixin(Generate!(B,A)); interface B : A { } abstract class C : B { } would it work if you define the interface but mixin the members? interface A { mixin(InterfaceFromClass!C); } Yes, I made a post about it but it didn't get through or I forgot to send ;/ Doing it this way solves the original problems but creates a new problem in that any class that inherits from an abstract class that implements A doesn't work. interface A { mixin(InterfaceFromClass!C); } abstract class B : A { A foo() { return this; } int bar() { return 3; } } class C : B { // compiler says foo, bar not implemented } so, instead interface A { mixin(InterfaceFromClass!C); } abstract class B { A foo() { return this; } // requires cast int bar() { return 3; } } class C : B, A { } works but requires casting this in B which happens to work in C. So It is a fessible solution but I'm not sure why the compiler things the first case doesn't implement the methods when it clearly does. I think it looks at A and doesn't compute the mixin first when parsing C because if I put the output of the mixin directly it works. Probably a bug... This method, which imports the source code and extracts the members works but is very fragile and requires using -J: // Directly copies the data to the interface with a few hacks to fix the bug from the original, it excepts a well formatted input template InterfaceFromClass(alias T) { string InterfaceFromClass(string file = __FILE_FULL_PATH__)() { string res; import std.path, std.string, std.algorithm; enum data = import(file.baseName); enum mc = "abstract class "~T.stringof~" : "; enum im = `@("InterfaceMembers")`; int level = 0; auto baseIndentLevel = -1; int funcIndentLevel = -1; foreach(v; data.splitLines) { string l = v; auto indentLevel = l.length - l.stripLeft().length; auto ll = l.strip(); if (ll.length == 0) continue; //res ~= to!string(l.length) ~"\n" ~ l[0..min(mc.length, l.length)] ~ "\n"; if (level == 0 && ll.length >= mc.length && ll[0..min(mc.length, ll.length)] == mc) { baseIndentLevel = indentLevel; level = 1; continue; } // Finds "abstract class : " if (level == 1 && ll.length >= im.length && ll[0..min(im.length, ll.length)] == im) { level = 2; continue; } // Finds "@("InterfaceMembers))" near by if (level >= 2 && l == "}") break; if (level == 2 && ll.length > 1) { if (funcIndentLevel < 0) funcIndentLevel = indentLevel; if (funcIndentLevel < indentLevel) continue; // A simple function definition(ends with a ');') if (!ll.canFind("=") && l.length > 2 && l[$-2..$] == ");") { res ~= l ~ "\n"; continue; } // ignore fields(assumes it has no {, } but ends with a ';') if (!ll.canFind("{") && l[$-1] == ';' && ll[$-2..$] != "};") continue; // ignore functions with inline blocks if (ll.canFind(") {")) { l = l[0..$ - ll.find(") {").length] ~ ")"; } // must get function signature only(ignore body) res ~= l ~ ((ll[$] != ';') ? ";" : "") ~ "\n"; } } return res; } } Why the original code is being broke by using D's traits to build the functions properly is beyond me. I'm pretty sure it is a bug given the example I gave earlier.
Re: full path to source file __FILE__
On Tuesday, 29 May 2018 at 21:41:37 UTC, Ali Çehreli wrote: On 05/29/2018 02:34 PM, DigitalDesigns wrote: > auto x(string fp = __FULL_FILE_PATH__)() { pragma(msg, fp); } ? __FILE_FULL_PATH__ https://dlang.org/spec/expression#specialkeywords Ali Lol, thanks:
Re: full path to source file __FILE__
On Wednesday, 27 July 2016 at 13:58:22 UTC, Jonathan Marler wrote: On Thursday, 21 July 2016 at 19:54:34 UTC, Jonathan Marler wrote: Is there a way to get the full path of the current source file? Something like: __FILE_FULL_PATH__ I'm asking because I'm rewriting a batch script in D, meant to be ran with rdmd. However, the script needs to know it's own path. The original batch script uses the %~dp0 variable for this, but I'm at a loss on how to do this in D. Since rdmd compiles the executable to the %TEMP% directory, thisExePath won't work. BATCH - echo "Directory of this script is " %~dp0 DLANG - import std.stdio; int main(string[] args) { writeln("Directory of this script is ", ???); } For others who may see this thread, the __FULL_FILE_PATH__ special trait was added to the dmd compiler with this PR: https://github.com/dlang/dmd/pull/5959 At the time of this post, the latest released version of D is 2.071.1, so this trait should be available on any release after that. Except it doesn't? auto x(string fp = __FULL_FILE_PATH__)() { pragma(msg, fp); } ?
string mixin output works when directly used but when generator is used D fails
https://dpaste.dzfl.pl/67691db19ce8 Just delete 9 to 29 for the code to work. Note that none of the code effects the output but D gives strange errors. In my code it says the interface members are not implemented(which they are) foreach (member; __traits(allMembers, T)) { static foreach (overload; MemberFunctionsTuple!(T, member)) { static if (__traits(getProtection, __traits(getMember, T, member)) == "public") { foreach(a; __traits(getAttributes, overload)) static if (is(typeof(a) == string) && a.length > 0 && a == "InterfaceMembers") { string q; foreach(b; __traits(getAttributes, overload)) static if (is(typeof(b) == string) && b.length > 0 && b == "InterfaceMembers") continue; else q ~= "@("~b.stringof~") "; //s ~= "\t"~q~cloneFunction!(overload, T) ~ ";\n"; } } } } is somehow breaking the interface. It should have no effect on it at all. Seems like a bug to me.
Re: Build interface from abstract class
On Tuesday, 29 May 2018 at 20:26:52 UTC, arturg wrote: On Tuesday, 29 May 2018 at 19:06:24 UTC, DigitalDesigns wrote: On Monday, 28 May 2018 at 22:15:40 UTC, arturg wrote: this might help you, https://dpaste.dzfl.pl/2cf844a11e3f you can use them to generate the functions as strings. Thanks, So, the problem I'm having is that I cannot use the generated interface for the abstract class because the abstract class needs the interface defined. I need to be able to forward define the interface then extend it. D doesn't like this main.d(10): Error: interface `main.B` base `A` is forward referenced interface A; mixin(Generate!(B,A)); interface B : A { } abstract class C : B { } would it work if you define the interface but mixin the members? interface A { mixin(InterfaceFromClass!C); } Yes, I made a post about it but it didn't get through or I forgot to send ;/ Doing it this way solves the original problems but creates a new problem in that any class that inherits from an abstract class that implements A doesn't work. interface A { mixin(InterfaceFromClass!C); } abstract class B : A { A foo() { return this; } int bar() { return 3; } } class C : B { // compiler says foo, bar not implemented } so, instead interface A { mixin(InterfaceFromClass!C); } abstract class B { A foo() { return this; } // requires cast int bar() { return 3; } } class C : B, A { } works but requires casting this in B which happens to work in C. So It is a fessible solution but I'm not sure why the compiler things the first case doesn't implement the methods when it clearly does. I think it looks at A and doesn't compute the mixin first when parsing C because if I put the output of the mixin directly it works. Probably a bug...
Re: Build interface from abstract class
On Monday, 28 May 2018 at 22:15:40 UTC, arturg wrote: this might help you, https://dpaste.dzfl.pl/2cf844a11e3f you can use them to generate the functions as strings. Thanks, So, the problem I'm having is that I cannot use the generated interface for the abstract class because the abstract class needs the interface defined. I need to be able to forward define the interface then extend it. D doesn't like this main.d(10): Error: interface `main.B` base `A` is forward referenced interface A; mixin(Generate!(B,A)); interface B : A { } abstract class C : B { } I could see that D wants A so it can have the complete picture for B, but this is one of those problems where it shouldn't matter. This requires hoops and ultimately does not solve the problem. Any time A is used it will be treated as undefined by the compiler and throw an error. For example: pragma(msg, InterfaceFromClass!(C, "A")); mixin(InterfaceFromClass!(C, "A")); interface B : A { } abstract class C { @("InterfaceMembers") { int xe = 3; @(3) void foo() { } @property int x() { return 3; }; B bar() { return null; } } } abstract class D : C, B { } fails because C.bar returns a B, which has not yet fully been defined because A has not yet fully been defined. Now, if I could just get the function signature without using the type system, this wouldn't be a problem. I don't really care if B is defined yet, I just need to know it's name. I guess D tries to enforce consistency at all steps, which is a problem here because C uses a yet to be defined type, even though it will be defined soon enough without problems. One of the main culprits is isCallable which is what errors out because of the yet to be defined B. So, I guess some other method will have to work.
Re: Build interface from abstract class
On Monday, 28 May 2018 at 11:51:20 UTC, Simen Kjærås wrote: On Monday, 28 May 2018 at 09:59:50 UTC, DigitalDesigns wrote: Implementing interfaces can be a pain but are necessary. I like to use abstract classes and provide a base implementation. It would be cool if I could use D's awesome meta features to extract the interface from the abstract class then build it. This requires some funky stuff which I'm not sure D can do Creating an interface based on a class is no big deal in D: interface Interface(T) { import std.traits; static foreach (fn; __traits(allMembers, T)) static foreach (overload; MemberFunctionsTuple!(T, fn)) mixin("ReturnType!overload "~fn~"(Parameters!overload);"); } class A { void fun() {} } alias IA = Interface!A; However, you run into a problem when A is expected to implement IA: in order to figure out which functions should be in the interface, we need to know which functions are in A. And in order to figure out which functions are in A, we need to know which functions are in IA. It's a loop with no real solution. In this specific case, one could consider only members of A, ignoring any interfaces or base classes. This isn't currently possible, but it's not an entirely unreasonable enhancement request. -- Simen I do not think this is a problem in D. Infinite recursion can always be terminated with appropriate means. 1. Use attributes. methods in class A should be marked as being for the interface. When added to the interface they will not have the attribute so will not be picked up again. 2. Your method of function creation does not pick up attributes and other factors so it is weak. Case 1 should be easy to deal with. Case 2, I am not so sure how to build the signature exactly as it is expressed. This is, of course, just a copy an paste mechanism but it would require D to provide us the signature in some way. Maybe an easy and direct way would be to pass __FILE__ and __LINE__ and extract the line? This seems a bit risky and slow. Case 1 Will not work if UDA's are required to be exactly the same between interface and class. I do not know if D enforces that but if it does it seems a bit overkill. Here is my solution that does not solve problem 2: import std.stdio; template InterfaceFromClass(alias T, string id) { auto InterfaceFromClass() { string s; import std.traits; foreach (member; __traits(allMembers, T)) { static foreach (overload; MemberFunctionsTuple!(T, member)) { enum attr = __traits(getAttributes, overload); static if (__traits(getProtection, __traits(getMember, T, member)) == "public") { mixin(`enum attrs = __traits(getAttributes, T.` ~ member ~ `);`); foreach(a; attrs) static if (is(typeof(a) == string) && a.length > 0 && a == "InterfaceMembers") { s ~= (ReturnType!overload).stringof ~" "~member~""~(Parameters!overload).stringof~";"; } } } } return "interface "~id~"\n{\n "~s~"\n}"; } } Which you can see it at work here: https://dpaste.dzfl.pl/f49be5dd7daa
Build interface from abstract class
Implementing interfaces can be a pain but are necessary. I like to use abstract classes and provide a base implementation. It would be cool if I could use D's awesome meta features to extract the interface from the abstract class then build it. This requires some funky stuff which I'm not sure D can do mixin(InterfaceFromAbstractClass!(MyAbstraction, "MyInterface")); interface MyInterface2 : MyInterface { final static void baz() { } } abstract class MyAbstraction : MyInterface2 { @InterfaceMembers { void foo() { }; } } InterfaceFromAbstractClass will get all the @InterfaceMembers members and declare them in an interface MyInterface. This avoids all the duplicate code that interfaces has to create. Is this possible in D?