Re: Language server
On Wednesday, 18 May 2022 at 01:04:16 UTC, Alain De Vos wrote: I tried neovim editor & serve-d and failed. I tried kate editor & serve-d and failed. https://github.com/Pure-D/serve-d Anyone has a clue ? I'm using [lunarvim](https://github.com/LunarVim/LunarVim). It provides you the ability to intall LSPs and treesitter parsers natively. Did you use `dub init` to create a project before trying to use `serve-d`? That could be why it doesn't work for you, maybe
I need to use delete as the method name. But now it's still a keyword, right?
https://dlang.org/changelog/2.100.0.html#deprecation_delete My code: ```D import std.stdio; class HttpClient { string get(string url) { return ""; } string delete(string url) { return ""; } } void main() { auto http = new HttpClient; string content = http.get("https://forum.dlang.org/group/general;); string content = http.delete("https://forum.dlang.org/newpost/general?;); } ``` error message ```bash % dub build --compiler=dmd Performing "debug" build using dmd for x86_64. test ~master: building configuration "application"... source/app.d(10,9): Error: no identifier for declarator `string` source/app.d(10,9): Error: declaration expected, not `delete` source/app.d(14,1): Error: unmatched closing brace dmd failed with exit code 1. ``` I wonder when I can use it. Because this will cause a software naming problem.
Re: Language server
I tried neovim editor & serve-d and failed. I tried kate editor & serve-d and failed. https://github.com/Pure-D/serve-d Anyone has a clue ?
Re: What are (were) the most difficult parts of D?
On Tuesday, 17 May 2022 at 06:28:10 UTC, cc wrote: having had this leave a pretty bad taste in my mouth, I now avoid the GC whenever possible, even when I don't have to. Bad idea. You should only avoid GC if your profiling shows that it is bad in a specific piece of code (e.g. some inner loop that's called millions of times - the real bottlenecks). This frees you from the mental load of thinking about memory allocation at all unless it becomes necessary, which it will actually be only in very, very few places. Better invest your precious time to really DO profiling and find out where the bottlenecks are! Maybe a run-and-done program can get along just fine allocating everything to the GC. But maybe I'll need to modularize it some day in the future and call it from another program with far more intensive requirements that doesn't want superfluous data being added to the GC every frame. Yes - and when you modularize your program, keep in mind that a module should avoid allocating anything large or often on its own at all. It should better work on memory given to it. So you remain able to decide on the calling side if you allocate by GC (default) or (if something turns out to be a bottleneck) manually allocate memory. Far better to just keep your house clean every day than let the trash pile up and wait for the maid to come, IMO. Inevitably it's going to be her day off when you have guests coming over. There's always gc.collect, which calls the maid to do her job, even if she is on vacation. Do so whenever you think you may have piled on a lot of trash and are out of house (have the time available that a collection may take). This way you can be sure there is never too much trash, so the GC is very unlikely to ever disturb you when there is no time for long collection cycles.
Re: Question on shapes
On Tuesday, 17 May 2022 at 09:30:12 UTC, forkit wrote: On Tuesday, 17 May 2022 at 04:37:58 UTC, Ali Çehreli wrote: In you OOP example, I am curious why you chose Shape to be an interface, rather than a base class. You can inherit from multiple interfaces, but only from one base class. So if you need multiple inheritance, better use interfaces. Especially at the first level of objects I would almost always use only interfaces, no classes. I consider this better design.
Re: undefined reference to `const const(char)[] object.Throwable.message()
As far as I know, no D compiler guarantees compatibility between objects built on different version of itself. The change would have been[0]. [0] https://github.com/dlang/druntime/commit/c6762914682d4fa894e2b746bf4bd9ce3ec9f7cb
undefined reference to `const const(char)[] object.Throwable.message()
I am compiling some test code which dmd v2.100.and linking against a libdecimal.a compiled in March, probably compiled with dmd v2.099.0. ``` $ dmd -g mytest.d decimal.git/libdecimal.a ``` Now the linker complains: ``` decimal.git/libdecimal.a(decimal_4f_a27.o):(.data._D7decimalQi25InvalidOperationException6__vtblZ+0x48): undefined reference to `_D6object9Throwable7messageMxFZAxa' decimal.git/libdecimal.a(decimal_50_94f.o):(.data._D7decimalQi23DivisionByZeroException6__vtblZ+0x48): undefined reference to `_D6object9Throwable7messageMxFZAxa' decimal.git/libdecimal.a(decimal_51_703.o):(.data._D7decimalQi17OverflowException6__vtblZ+0x48): undefined reference to `_D6object9Throwable7messageMxFZAxa' decimal.git/libdecimal.a(decimal_52_765.o):(.data._D7decimalQi18UnderflowException6__vtblZ+0x48): undefined reference to `_D6object9Throwable7messageMxFZAxa' decimal.git/libdecimal.a(decimal_53_67b.o):(.data._D7decimalQi16InexactException6__vtblZ+0x48): undefined reference to `_D6object9Throwable7messageMxFZAxa' decimal.git/libdecimal.a(decimal_4e_65e.o):(.data._D7decimalQi16DecimalException6__vtblZ+0x48): more undefined references to `_D6object9Throwable7messageMxFZAxa' follow collect2: ld returned 1 exit status Error: linker exited with status 1 ``` which demangles to ``` decimal.git/libdecimal.a(decimal_4e_65e.o):(.data.decimal.decimal.DecimalException.__vtbl+0x48): more undefined references to `const const(char)[] object.Throwable.message()' follow ``` When switching back to dmd v2.099.1 linking succeeds. Could not find any hint in https://dlang.org/changelog/2.100.0.html.
Re: decimal type in d
On Monday, 16 May 2022 at 09:59:41 UTC, bauss wrote: On Monday, 16 May 2022 at 09:46:57 UTC, IGotD- wrote: On Sunday, 15 May 2022 at 13:26:30 UTC, vit wrote: [...] This also something I wondered, it should be standard in the D library. Implementing it can be done straight forward with existing D language primitives, essentially a struct. For those who don't know, decimal in C# is like a floating point value but the exponent is a power of 10 (internally total 16 bytes). This means that for "simple" mathematics rational decimal values remains rational decimals values and not some rounded value that would happen if you would use normal floating point values. The decimal type is essential for financial calculations. I think D can more or less copy the C# solution. Here's the implementation if anyone needs it: https://referencesource.microsoft.com/#mscorlib/system/decimal.cs,1b2858baf311cbf9 Should be fairly straightforward to implement. Thanks, but it is not full implementation of decimal, arithmetic operator are missing. On Monday, 16 May 2022 at 16:41:33 UTC, Steven Schveighoffer wrote: On 5/15/22 9:26 AM, vit wrote: Hello, I want read decimal type from sql db, do some arithmetic operations inside D program and write it back to DB. Result need to be close to result as if this operations was performed in sql DB. Something like C# decimal. Exists this kind of library ind D? (ideally `pure @safe @nogc nothrow`). https://code.dlang.org/search?q=decimal -Steve Thanks, most of the packages are incomplete or too old (doesn't compile), but this one https://code.dlang.org/packages/decimal can by modified to work for my use.
Re: Why are structs and classes so different?
On Monday, 16 May 2022 at 21:20:43 UTC, Ali Çehreli wrote: On 5/16/22 10:35, Johan wrote: > What is very problematic is that you cannot see the difference in > syntax. In my opinion it would have been much better if the language > required using a `*` for class types: for example `Foo* a`, and `Foo a` > would simply give a compile error. I see. Is it really a high mental load without the syntax? I seems to just work in my programs but perhaps because I am the main programmer and classes are very rare anyway. Also, same syntax is said to help with template code but perhaps the argument there is a template must be written either for value types or reference types? I am not sure. `Foo a = b;` What does that do? A benefit of statically typed languages is that you know what simple code will do. But for this simple statement, you actually don't know. Perhaps it is a copy, perhaps not. I understand that also structs can have reference-like semantics with copies if they contain pointers, but it is strange that the language at a fundamental basic level has this ambiguity of user types. Indeed the same-syntax template argument is bogus, for exactly this reason that you don't know what the code is doing. If the language deems it important enough to separate value types from reference types, then why does it allow passing _both_ to `foo(T)(T t)` ? -Johan
Re: Why are structs and classes so different?
On 5/17/22 07:40, Kevin Bailey wrote: > Foo foo; > > is undefined behavior waiting to happen, that I can't detect at a glance. Foo is null there. (I don't remember whether accessing through null reference is undefined or segmentation fault (on common systems).) Using foo will not do some random thing. > - A *secondary* goal would be for class objects to be able to have > deterministic destructors like structs. I understand. D uses garbage collection by default for classes. Having this choice of struct versus class is useful. This has been mentioned before: structs are the predominant user-defined type in D. Classes are only for polymorphic behavior. >> C++ does not use terms "value type" and "reference type" to make any >> distinction but the rules above are proof enough for me that C++ >> implicitly divides user-defined types into such categories. > > I would beg to differ here. In C++, all types are value types, until you > add punctuation. This is one of the things that I like about C++, that I > trip over in other languages. e.g. In Rust, there are 2 similar types, > is it int and float, where one is copyable and the other move-only? How > can you write generic code in that environment? > > Yes, in C++, you have to worry about slicing and copying singletons, but > these are problems in front of you. It's the problems that sneak up > behind you that I worry about. Yes, that's where we differ. :) You see problems that can sneak up, I see problems disappeared. >> Ok, I think I see better now. You would like members of a class >> recursively placed next to each other in memory. What if a polymorphic >> type had a polymorphic member? > > You mean like a string? I don't have a problem with this: > > class MyString { > uint length; > ...pointer to data... > } > > void func() { > MyString s; It is easy to adapt to the following syntax: auto s = /* some expression */; auto s = new MyString(); auto s = scoped!MyString(); scope s = new MyString(); MyString could have been a member variable, which would be initialized in a constructor (or not; everything gets the .init value). > if (s.length == 0) // I want this to be perfectly safe. >writeln("empty"); > // 's' destroyed here, could do something useful Such types are rare in my experience especially because of the GC. Once you remove explicit freeing of memory, most destructors disappear as well. In cases where deterministic destruction is needed, we have a number of options all of which were used by me: - scope has already been mentioned. - RAII: MyString could be owned by a struct (e.g. MyStringCloser) either for every use or wherever it makes sense. - scope (exit) { s.close(); } > } > > In D, some objects can do this; some can't! Perhaps in a template, yes. Then we may have to do some introspection there: static if (is (T == class)) { auto s = new T(); } else { auto S = T(); } I've seen similar concerns raised about this difference before. Just checked: Yes, there are 45 occurrences of that check under /usr/include/dlang/dmd on my system, which includes Phobos and core. > Python is a toy language, right? I'm not aware of any large projects in > it. (The largest I worked with was 138 files, 31k lines - tiny.) Wow! That's way beyond my pay grade. :) But I have a feeling you will like D despite its differences. > Perhaps the project is small. Correct. I would be happy if others chimed in but this struct/class difference is not a common issue with D at all. > Perhaps your IDE colors classes > brightly. Yes, I use syntax highlighting with muted colors. :) I still use Emacs with a suboptimal configuration. (I need to work on fixing that already. :/) Ali
Re: Why are structs and classes so different?
On Tuesday, 17 May 2022 at 14:40:48 UTC, Kevin Bailey wrote: Foo foo; is undefined behavior waiting to happen, that I can't detect at a glance. It is actually perfectly well defined - for the class, it will be null, and this will kill the program if you use it. You might not like that definition, but that's how it is defined. - A *secondary* goal would be for class objects to be able to have deterministic destructors like structs. they can with the `scope` keyword. The first looks trivial: Just have it allocate a Foo by default. Worth noting that D *never* calls a user defined function on variable declaration; there are no default constructors. Even if it is a struct, it never actually calls a constructor, it just copies over the default init value. This is different than classes, which have some kind of constructor call any time you make one. I think it is probably this default constructor stance that the rest flows from: a class is assumed to encapsulate some non-trivial state so it has a constructor, interfaces, object identities, etc. A struct is more of a plain collection of data. Of course, in practice the lines are more blurred than that, but I think that's where it comes from. Especially if you look at the older D versions when structs didn't support constructors at all.
Re: Why are structs and classes so different?
Hi again Ali! On Monday, 16 May 2022 at 21:58:09 UTC, Ali Çehreli wrote: I for one misunderstood you. I really thought you were arguing that struct and class should be the same. To be specific: - My *primary* concern is that: Foo foo; is undefined behavior waiting to happen, that I can't detect at a glance. - A *secondary* goal would be for class objects to be able to have deterministic destructors like structs. The first looks trivial: Just have it allocate a Foo by default. The second looks like it could have been designed that way, albeit with other minor changes to the language, and, I was curious why it wasn't. C++ is proof that it can indeed work the other way. However, for it to work correctly, programmers must follow guidelines. Here are four: But again, from this discussion, it seems D could have simply had pass-by-reference for class objects, preserving everything D strives for, but by-value stack initialization, providing what people expect from stack objects. There's no need to drag C++ design into it. C++ does not use terms "value type" and "reference type" to make any distinction but the rules above are proof enough for me that C++ implicitly divides user-defined types into such categories. I would beg to differ here. In C++, all types are value types, until you add punctuation. This is one of the things that I like about C++, that I trip over in other languages. e.g. In Rust, there are 2 similar types, is it int and float, where one is copyable and the other move-only? How can you write generic code in that environment? Yes, in C++, you have to worry about slicing and copying singletons, but these are problems in front of you. It's the problems that sneak up behind you that I worry about. Ok, I think I see better now. You would like members of a class recursively placed next to each other in memory. What if a polymorphic type had a polymorphic member? You mean like a string? I don't have a problem with this: class MyString { uint length; ...pointer to data... } void func() { MyString s; if (s.length == 0) // I want this to be perfectly safe. writeln("empty"); // 's' destroyed here, could do something useful } In D, some objects can do this; some can't! I don't understand that example. I see a programmer error of casting a Foo to a Bar. Correct, I was responding to a comment. I was pointing out that the only "slicing" that we need to worry about with by-reference is if we are already doing something wrong, and that D won't help you there. Did you mean C#? C# is like D: structs are value types and classes are reference types. You missed the part where I said, "ignoring structs". :-) With all due respect, based on other conversation here, may I assume you those projects were based on C++? If you also had any language with reference types like Python, did you have the similar issues with those languages? Python is a toy language, right? I'm not aware of any large projects in it. (The largest I worked with was 138 files, 31k lines - tiny.) Java would be a better comparison, but it has auto-closable objects, unlike D and Python. Perhaps it has succeeded because there are so few types that *aren't* by reference. Perhaps one just gets used to it. (I've written Android apps, but I would never write a long-running service in it.) This is unfortunate for D where you have to keep track. I accepted D's struct/class separation since the beginning and never had any issue with it. It just worked for me. Perhaps you are familiar with the types that you work with on a daily basis. Perhaps the project is small. Perhaps your IDE colors classes brightly. I don't know, but an anecdote doesn't mean much compared to the fact that nearly all large projects are in C++, and I don't mean "due to inertia." I mean, "and they're successful."
Re: Question on shapes
On 5/17/22 02:30, forkit wrote: > On Tuesday, 17 May 2022 at 04:37:58 UTC, Ali Çehreli wrote: >> > > In you OOP example, I am curious why you chose Shape to be an interface, > rather than a base class. I always have the same question. :) interface feels lighterweight, so it is an arbitrary decision for me. I haven't hit any situation where a class would be needed. One difference is, class requires the 'override' keyword in the subclasses. I really don't know any technical difference. Ali
Re: What are (were) the most difficult parts of D?
On Tuesday, 17 May 2022 at 11:53:40 UTC, zjh wrote: On Tuesday, 17 May 2022 at 11:50:30 UTC, zjh wrote: Right,GC is a bad idea! Endless use of memory without freeing. It's totally unreasonable waste. It's not really endless use of memory and it does free. Depending on the strategy then it does so at different times, such as when allocating, but not enough memory has been allocated already. The problem with GC is that the lifetime sometimes exceed what's expected. Personally I don't have a problem with the GC.
Re: What are (were) the most difficult parts of D?
On Tuesday, 17 May 2022 at 11:50:30 UTC, zjh wrote: Right,GC is a bad idea! Endless use of memory without freeing. It's totally unreasonable waste.
Re: D WebAssembly working differently than C++, Zig
On Tuesday, 17 May 2022 at 11:43:45 UTC, Siarhei Siamashka wrote: Looks like you forgot to increment the pointer and need "*d++ = cast(ubyte) c;" there. hahaha yup. And filling the buffer one byte at a time is likely slow. prolly but meh, that's where the intrinsics are nice.
Re: What are (were) the most difficult parts of D?
On Tuesday, 17 May 2022 at 06:28:10 UTC, cc wrote: Far better to just keep your house clean every day than let the trash pile up and wait for the maid to come, IMO. Right,GC is a bad idea!
Re: D WebAssembly working differently than C++, Zig
On Tuesday, 17 May 2022 at 11:36:21 UTC, Adam D Ruppe wrote: Oh I should have checked my impl, where I did all this already! https://github.com/adamdruppe/webassembly/blob/master/arsd-webassembly/object.d#L263 Looks like you forgot to increment the pointer and need "*d++ = cast(ubyte) c;" there. And filling the buffer one byte at a time is likely slow.
Re: D WebAssembly working differently than C++, Zig
On Monday, 16 May 2022 at 18:17:03 UTC, Allen Garvey wrote: Thanks so much, that fixed the problem! You have no idea have long I have spent trying to debug this! Oh I should have checked my impl, where I did all this already! https://github.com/adamdruppe/webassembly/blob/master/arsd-webassembly/object.d#L263 And also might be able to just have the function forward to the ldc intrinsic: https://github.com/ldc-developers/druntime/blob/ldc/src/ldc/intrinsics.di#L160 might help speed up a lil too, i don't know though (I didn't do it here for me)
Re: Why doesn't this piece of code work?
On Monday, 16 May 2022 at 22:25:23 UTC, kdevel wrote: On Monday, 16 May 2022 at 16:53:15 UTC, SvGaming wrote: [...] [...] In main your program reads an integer: ``` int n; writef("Pick an option: "); readf(" %s", ); ``` [...] Just tried the solution and it works perfectly! Thanks, Again!
Re: D WebAssembly working differently than C++, Zig
On Tuesday, 17 May 2022 at 09:38:31 UTC, Sergey wrote: On Monday, 16 May 2022 at 17:32:20 UTC, Allen Garvey wrote: I'm working on a comparison of WebAssembly performance for error propagation dithering using D, C++ and Zig. So far C++ and Zig work as expected, but for D, despite using the same algorithm and similar code the output is different. Hm D version is the slowest one?! It's faster than the JS version atleast. But yeah, C++ and Zig being 30+% faster than the D solution doesn't look good on us :(
Re: D WebAssembly working differently than C++, Zig
On Monday, 16 May 2022 at 17:32:20 UTC, Allen Garvey wrote: I'm working on a comparison of WebAssembly performance for error propagation dithering using D, C++ and Zig. So far C++ and Zig work as expected, but for D, despite using the same algorithm and similar code the output is different. Hm D version is the slowest one?!
Re: Question on shapes
On Tuesday, 17 May 2022 at 04:37:58 UTC, Ali Çehreli wrote: In you OOP example, I am curious why you chose Shape to be an interface, rather than a base class.
Re: What are (were) the most difficult parts of D?
On Monday, 16 May 2022 at 15:08:15 UTC, H. S. Teoh wrote: If you find yourself having to cast to/from immutable, you're using it wrong. I clearly was, which is why I'm not using it anymore. The question was "What are you stuck at? What was the most difficult features to understand? etc.", so I listed the things that tripped me up in my early time with D. I assumed the context of this was collecting useful information for, say, understanding what newcomers' sticking points are and maybe thinking how to make D more accessible to them. Maybe this wasn't the intent, but this kind of comes across more as a lecture on how everything I was doing wrong is my own fault even when I've already stated I'm *not doing those things anymore*. I write D programs that process input files all the time, including stuffing data into AAs and what-not, and it Just Works(tm). Of course it just works, why wouldn't it? But not once did I bother with immutable (why should I?). Because the documentation crams it down your throat. Or at least it did, along with the early blog/wiki posts that were the only source of D information I could find back at the time. And yes, I pored over that page on the differences between const and immutable years ago, which sang immutable's praises at length, how it was D's greatest innovation to set it apart from C++, and implied it should be slapped on literally everything that never changes and how great this was for multithreading, hence why I (formerly) felt the need to try and define all my persistent definitions as immutable. Now I slap __gshared on everything and just let it go. For anything performance-related, I don't even look at dmd, I use LDC all the way. DMD is only useful for fast compile-run-debug cycle, I don't even look at performance numbers for DMD-produced executables, it doesn't mean anything to me. According to the dlang.org wiki entry for LDC: druntime/Phobos support is most likely lacking (and probably requires a new version predefined by the compiler). So I'm not touching it for now. Don't have time to investigate a completely new compiler and track down incompatibilities when DMD works and I've been invested in it. The fact that LDC is more performant than DMD surely not does imply attempting to optimize DMD-compiled programs is futile. My use of immutable was based in part on a (mistaken) assumption that this was a recommended best practice for multithreading safety and performance. Just make things private and use getters/setters to control access. Like I said, if you find yourself writing lots of casts Equally irritating. Direct access is far less annoying to write. Yes, I could use mixins to automate some of this but it still uglifies the code even more to no great advantage for my purposes. Getters/setters have always felt relevant only to large team environments, when you can't count on another developer knowing certain things aren't meant to be touched. For simple self-protection, I like C#'s "readonly" keyword, as I said. Statement of opinion. I wish D had something similarly painless to use, but it doesn't, so I'm out of luck. I just direct access and try to not make mistakes instead. Why would you want to force deterministic memory management onto GC-allocated objects? Just use malloc/free (or whatever else Because when I first got into D this was *not made clear*. The GC was sold so heavily and every single non-GC approach to memory management was made to look like, at best, a crude circumvention, and at worst a pariah. In C++ I could new/delete, in ObjC I had alloc/autorelease, D had new, and also delete at the time, which was not adequately explained that it pretty much did nothing, and even then it (and its hacky replacement __delete) were bugged anyway. Perhaps this was my own ignorance, fair enough. NOW I already use malloc/free for everything important. But is this helpful to future newcomers? Wait till they screw up, don't understand why, then tell them after the fact they were doing it wrong, if they're still around by that point? To this day, as your post demonstrates, the GC is still extolled as the correct solution to 99% of problems, with alternatives only grudgingly admitted to after a person reports running into problems. On top of this, at the time I got into D, the GC just plain DIDN'T work for arbitrary chunks of data unless you carefully zeroed them out. I could easily write trivial programs to read a binary file's raw data into an array of ubyte[], let it go out of scope without any escaped pointers, and crash with out of memory as the loop cheerfully ate up 8+ GB. The move to 64-bit and whatever bugfixes may have happened in the past years helped and fortunately everything "Just Works" NOW. But back then, it didn't. So when on top of this my programs started having disastrous performance issues due to GC collections because the
Re: Question on shapes
On Tuesday, 17 May 2022 at 05:08:30 UTC, matheus wrote: In D there would be a better way to do such thing? Nothing really specific to D, but for one or two properties, you might just add them as function parameters with default values: ```d void draw(float scale = 1.0f); ``` If you have a number of them (scale, color, blend state, etc.), then you might add them as members of the `Shape` class. You could then expand on that with a single draw function in the `Shape` class that handles the actual drawing, and the subclasses would then call that internally after, e.g., setting up any vertex buffers or whatever specific to the shapes. ```d class Shape { private: float scale; RGBA color; DrawBuffer buffer; // some API-specific vertex buffer or whatever protected: void drawImpl() { // get the shape on screen } public: abstract void draw(); } class Circle { override void draw() { // set up buffer ... drawImpl(); } ``` Or you could have a `DrawProperties` struct independent of the `Shape` hierarchy that you can fill out and pass to every draw call. Or set global properties in the renderer and draw objects that have the same properties all at once. There are several ways to go about it.
Re: Question on shapes
On Tuesday, 17 May 2022 at 00:10:55 UTC, Alain De Vos wrote: Let's say a shape is ,a circle with a radius ,or a square with a rectangular size. I want to pass shapes to functions, eg to draw them on the screen, draw(myshape) or myshape.draw(); But how do i implement best shapes ? In addition to all the answers, just remember that if you want to make a square class then it should inherit from the shape class and not the rectangle class. It might seem like the obvious rule is for square to inherit rectangle, since a square is a rectangle, but it's only true on the surface, not in functionality. An example is below: ```d void changeRectangle(Rectangle rectangle, int amount) { rectangle.length = rectangle.length + amount; } ... // While this works, then it's functional wrong as you must change both the length/height of a square, since they cannot differ. changeRectangle(new Square(100, 100), 50); ``` You might think that it's easy to just not call changeRectangle with a square, but what if you store the rectangles in a list, map, get it from an external data source etc. then it starts being more and more complex and for no reason at all! I know your post really isn't about such things, but I think it's a good thing to learn already.
Re: Question on shapes
On 5/16/22 22:08, matheus wrote: > interface Shape { >void draw(); >void draw(float scale); > } Interfaces can have 'final' functions: interface Shape { void draw(float scale); final void draw() { draw(1); } } Obviously, for that to work, now Circle.draw() etc. required to respond to a 'scale' parameter. > In D there would be a better way to do such thing? Reminding that class hierarchies can be deeper as well: interface A {} class B : A { void foo() {} } class C : B { override void foo() {} } Ali