Creating a new type, to get strong-ish type checking and restrict usage to certain operations, using struct perhaps
I was think about how to create a new type that holds packed bcd values, of a choice of widths, that must fit into a uint32_t or a uint64_t (not really long multi-byte objects). I am not at all sure how to do it. I thought about using a templated struct to simply wrap a uint of a chosen width, and perhaps use alias this to make things nicer.
Re: Creating a new type, to get strong-ish type checking and restrict usage to certain operations, using struct perhaps
On Friday, 21 July 2017 at 18:49:21 UTC, Cecil Ward wrote: I was think about how to create a new type that holds packed bcd values, of a choice of widths, that must fit into a uint32_t or a uint64_t (not really long multi-byte objects). I am not at all sure how to do it. I thought about using a templated struct to simply wrap a uint of a chosen width, and perhaps use alias this to make things nicer. I guess part of my question, which I didn't really highlight well enough, is the issue of strong typing. Example: physical units types, such as amps and volts, implemented as say a double or float or real (want to template that) but disallow evil assignments, comparisons, addition etc of mixed types. Another one would be the prevention of mixing pounds and pence by straight addition, or straight comparisons and blocking straight assignment. I'm assuming in the latter case you might use a machine-architecture native integral type of whatever width, again templating wanted. These are all really old requests, I'm sure, but I would appreciate a start as to how to implement the strong type checking in D without too much pain. Going back to the original example of packed bcd stored in a uint64_t say, first thing is that I want to ban illegal mixing of arbitrary binary values in ordinary uint64_tmtypes with decimal types, again no assignment, addition, comoarisons etc across types at all allowed. And no friendly automagically conversions from packed bcd to binary on the fly either - I want to treat that kind of usage as a straight bug by the user, for the moment at least, anyway, as I don't want to encourage silent horrible inefficiency creeping in.
Re: Creating a new type, to get strong-ish type checking and restrict usage to certain operations, using struct perhaps
On Saturday, 22 July 2017 at 03:18:29 UTC, Cecil Ward wrote: [...] I saw David Nadlinger's units package. I'd like to know how the strong typing works.
Bug or not? Statics inside blocks
The snippet below failed to compile (I think) in the latest DMD - but I can't see the error message in the web-based editor at dlang.org. It certainly failed to compile under GDC 5.2.0 when tried out using d.godbolt.org. (Is there any chance of a later GDC compiler there?) Is it my bug, or a compiler bug? (name clash at link-time?): void main() { { immutable static dstring str1 = "a"; } { immutable static dstring str1 = "b"; } }
Re: Bug or not? Statics inside blocks
On Saturday, 29 July 2017 at 01:54:29 UTC, Cecil Ward wrote: The snippet below failed to compile (I think) in the latest DMD - but I can't see the error message in the web-based editor at dlang.org. It certainly failed to compile under GDC 5.2.0 when tried out using d.godbolt.org. (Is there any chance of a later GDC compiler there?) Is it my bug, or a compiler bug? (name clash at link-time?): void main() { { immutable static dstring str1 = "a"; } { immutable static dstring str1 = "b"; } } Workaround is just to rename one, assuming that avoids a name clash at -time.
Specify rhs at initialisation or assignment of typedef' d variable
Say I have used Typedef! to create some new type and I declare a variable, constant or enum of that type. Is there a way that I can express a literal value on the rhs without having to use casts, as that seems to defeat the point of the nice type safety? I may be asking for the impossible or _illogical_ here. In any case, I still get to keep the nice feature of not being able to mix up types with assignment from one variable to another. Specific example is mac_addr_48_t my_mac_address = 0x112233445566uL; Which now produces a compile time error after I changed to use an alias = Typedef!uint64_t as opposed to just a straight alias = uint64_t earlier with no strong typing.
Re: Specify rhs at initialisation or assignment of typedef' d variable
On Monday, 31 July 2017 at 07:50:57 UTC, inevzxui wrote: On Monday, 31 July 2017 at 07:16:25 UTC, Cecil Ward wrote: Say I have used Typedef! to create some new type and I declare a variable, constant or enum of that type. Is there a way that I can express a literal value on the rhs without having to use casts, as that seems to defeat the point of the nice type safety? I may be asking for the impossible or _illogical_ here. In any case, I still get to keep the nice feature of not being able to mix up types with assignment from one variable to another. Specific example is mac_addr_48_t my_mac_address = 0x112233445566uL; Which now produces a compile time error after I changed to use an alias = Typedef!uint64_t as opposed to just a straight alias = uint64_t earlier with no strong typing. If struct + alias this is not strong enough the only solution is see is a helper template à la "octal" or "hexString", i.e a static cally checked string. I suspect that I am asking for something that literally makes no sense at all. I wanted to try and avoid opening the door to allowing the following kind of typing error now, eg enum ip_address = 0x11223344; mac_addr_48_t my_mac = cast(mac_addr_48_t) ip_address; as if we are going to the bother of introducing strong type checking with Typedef! then the last thing I want to do is encourage is a proliferation of casts. I realise something else now too - Issue 2: The thing is that I also immediately have to do a lot of work to make the simplest operators work anyway, such as in foreach( addr; base_mac_address .. base_mac_address + range ) where the + operator is producing compile-time errors now. So it just seems that the Typedef! feature immediately make life into a nightmare. I don't know if something based of the physical units module (using 'dimensionless' in this case) would work - perhaps it only handles floating point of various types? Or whether that would also involve a huge amount of work and still have issue 1 mentioned earlier. In any case, I have absolutely no clue how to even begin to start using the units module thing.
Re: Specify rhs at initialisation or assignment of typedef' d variable
On Monday, 31 July 2017 at 08:53:10 UTC, Cecil Ward wrote: On Monday, 31 July 2017 at 07:50:57 UTC, inevzxui wrote: [...] I suspect that I am asking for something that literally makes no sense at all. I wanted to try and avoid opening the door to allowing the following kind of typing error now, eg enum ip_address = 0x11223344; mac_addr_48_t my_mac = cast(mac_addr_48_t) ip_address; as if we are going to the bother of introducing strong type checking with Typedef! then the last thing I want to do is encourage is a proliferation of casts. [...] Actually, it would be really nice to have some kind of safe initialisation helper that checks value ranges, as in this particular case I need to make sure that the literal 64-bit value fits in 48 bits.
Re: (SIMD) Optimized multi-byte chunk scanning
On Friday, 25 August 2017 at 18:52:57 UTC, Nordlöw wrote: On Friday, 25 August 2017 at 09:40:28 UTC, Igor wrote: As for a nice reference of intel intrinsics: https://software.intel.com/sites/landingpage/IntrinsicsGuide/ Wow, what a fabulous UX! The pcmpestri instruction is probably what you are looking for? There is a useful resource in the Intel optimisation guide. There is also an Intel article about speeding up XML parsing with this instruction, but if memory serves it's really messy - a right palaver. A lot depends on how much control, if any you have over the input data, typically none I quite understand. Based on this article, https://graphics.stanford.edu/~seander/bithacks.html I wrote a short d routine to help me learn the language as I was thinking about faster strlen using larger-sized gulps. The above article has a good test for whether or not a wide word contains a particular byte value somewhere in it. I wrote a bool hasZeroByte( in uint64_t x ) function based on that method. I'm intending to write a friendlier d convenience routine to give access to inline pcmpestri code generation in GDC when I get round to it (one instruction all fully inlined and flexibly optimised at compile-time, with no subroutine call to an instruction). Agner Fog's libraries and articles are superb, take a look. He must have published code to deal with these C standard library byte string processing functions efficiently with wide aligned machine words, unless I'm getting very forgetful. A bit of googling?
No CTFE of function
I have a pure function that has constant inputs, known at compile-time, contains no funny stuff internally - looked at the generated code, and no RTL calls at all. But in a test call with constant literal values (arrays initialised to literal) passed to the pure routine GDC refuses to CTFE the whole thing, as I would expect it (based on previous experience with d and GDC) to simply generate a trivial function that puts out a block of CTFE-evaluated constant data corresponding to the input. Unfortunately it's a bit too long to post in here. I've tried lots of variations. Function is marked nogc safe pure nothrow Any ideas as to why GDC might just refuse to do CTFE on compile-time-known inputs in a truly pure situation? Haven't tried DMD yet. Can try LDC. Am using d.godbolt.org to look at the result, as I don't have a machine here to run a d compiler on. Other things I can think of. Contains function-in-a-function calls, which are all unlined out in the generated code nicely, and not the first time I've done that with GDC either. Switches: Am using -Os or -O2 or -O3 - tried all. Tuning to presume + enable the latest x86-64 instructions. release build, no bounds-checks.
Re: No CTFE of function
On Saturday, 26 August 2017 at 18:16:07 UTC, ag0aep6g wrote: On Saturday, 26 August 2017 at 16:52:36 UTC, Cecil Ward wrote: Any ideas as to why GDC might just refuse to do CTFE on compile-time-known inputs in a truly pure situation? That's not how CTFE works. CTFE only kicks in when the *result* is required at compile time. For example, when you assign it to an enum. The inputs must be known at compile time, and the interpreter will refuse to go on when you try something impure. But those things don't trigger CTFE. The compiler may choose to precompute any constant expression, but that's an optimization (constant folding), not CTFE. I think I understand, but I'm not sure. I should have explained properly. I suspect what I should have said was that I was expecting an _optimisation_ and I didn't see it. I thought that a specific instance of a call to my pure function that has all compile-time-known arguments would just produce generated code that returned an explicit constant that is worked out by CTFE calculation, replacing the actual code for the general function entirely. So for example auto foo() { return bar( 2, 3 ); } (where bar is strongly pure and completely CTFE-able) should have been replaced by generated x64 code looking exactly literally like auto foo() { return 5; } expect that the returned result would be a fixed-length literal array of 32-but numbers in my case (no dynamic arrays anywhere, these I believe potentially involve RTL calls and the allocator internally).
Re: No CTFE of function
On Saturday, 26 August 2017 at 23:49:30 UTC, Cecil Ward wrote: On Saturday, 26 August 2017 at 18:16:07 UTC, ag0aep6g wrote: On Saturday, 26 August 2017 at 16:52:36 UTC, Cecil Ward wrote: Any ideas as to why GDC might just refuse to do CTFE on compile-time-known inputs in a truly pure situation? That's not how CTFE works. CTFE only kicks in when the *result* is required at compile time. For example, when you assign it to an enum. The inputs must be known at compile time, and the interpreter will refuse to go on when you try something impure. But those things don't trigger CTFE. The compiler may choose to precompute any constant expression, but that's an optimization (constant folding), not CTFE. I think I understand, but I'm not sure. I should have explained properly. I suspect what I should have said was that I was expecting an _optimisation_ and I didn't see it. I thought that a specific instance of a call to my pure function that has all compile-time-known arguments would just produce generated code that returned an explicit constant that is worked out by CTFE calculation, replacing the actual code for the general function entirely. So for example auto foo() { return bar( 2, 3 ); } (where bar is strongly pure and completely CTFE-able) should have been replaced by generated x64 code looking exactly literally like auto foo() { return 5; } expect that the returned result would be a fixed-length literal array of 32-but numbers in my case (no dynamic arrays anywhere, these I believe potentially involve RTL calls and the allocator internally). I was expecting this optimisation to 'return literal constant only' because I have seen it before in other cases with GDC. Obviously generating a call that involves running the algorithm at runtime is a performance disaster when it certainly could have all been thrown away in the particular case in point and been replaced by a return of a precomputed value with zero runtime cost. So this is actually an issue with specific compilers, but I was wondering if I have missed anything about any D general rules that make CTFE evaluation practically impossible?
Re: No CTFE of function
On Saturday, 26 August 2017 at 23:53:36 UTC, Cecil Ward wrote: On Saturday, 26 August 2017 at 23:49:30 UTC, Cecil Ward wrote: [...] I was expecting this optimisation to 'return literal constant only' because I have seen it before in other cases with GDC. Obviously generating a call that involves running the algorithm at runtime is a performance disaster when it certainly could have all been thrown away in the particular case in point and been replaced by a return of a precomputed value with zero runtime cost. So this is actually an issue with specific compilers, but I was wondering if I have missed anything about any D general rules that make CTFE evaluation practically impossible? I suspect I posted this in the wrong category completely, should have been under GDC (poss applies to LDC too, will test that)
Re: No CTFE of function
On Sunday, 27 August 2017 at 00:20:47 UTC, ag0aep6g wrote: On 08/27/2017 01:53 AM, Cecil Ward wrote: On Saturday, 26 August 2017 at 23:49:30 UTC, Cecil Ward wrote: [...] I think I understand, but I'm not sure. I should have explained properly. I suspect what I should have said was that I was expecting an _optimisation_ and I didn't see it. I thought that a specific instance of a call to my pure function that has all compile-time-known arguments would just produce generated code that returned an explicit constant that is worked out by CTFE calculation, replacing the actual code for the general function entirely. So for example auto foo() { return bar( 2, 3 ); } (where bar is strongly pure and completely CTFE-able) should have been replaced by generated x64 code looking exactly literally like auto foo() { return 5; } expect that the returned result would be a fixed-length literal array of 32-but numbers in my case (no dynamic arrays anywhere, these I believe potentially involve RTL calls and the allocator internally). I was expecting this optimisation to 'return literal constant only' because I have seen it before in other cases with GDC. Obviously generating a call that involves running the algorithm at runtime is a performance disaster when it certainly could have all been thrown away in the particular case in point and been replaced by a return of a precomputed value with zero runtime cost. So this is actually an issue with specific compilers, but I was wondering if I have missed anything about any D general rules that make CTFE evaluation practically impossible? I don't know what might prevent the optimization. You can force (actual) CTFE with an enum or static variable. Then you don't have to rely on the optimizer. And the compiler will reject the code if you try something that can't be done at compile time. Example: auto foo() { enum r = bar(2, 3); return r; } Please don't use the term "CTFE" for the optimization. The two are related, of course. The optimizer may literally evaluate functions at compile time. But I think we better reserve the acronym "CTFE" for the guaranteed/forced kind of precomputation, to avoid confusion. Static had already been tried. Failed. Thanks to your tip, I tried enum next. Failed as well, wouldn't compile with GDC. I tried LDC, which did the right thing in all cases. Optimised correctly in every use case to not compute in the generated code, just return the literal compile-time calculated result array by writing a load of immediate values straight to the destination. Hurrah for LDC. Then tried DMD via web-based edit/compile feature at dlang.org website. Refused to compile in the enum case and actually told me why, in a very very cryptic way. I worked out that it has a problem internally (this is a now an assignment into an enum, so I have permission to use the term CTFE now) in that it refuses to do CTFE if any variable is declared using an =void initialiser to stop the wasteful huge pre-fill with zeros which could take half an hour on a large object with slow memory and for all I know play havoc with the cache. So simply deleting the = void fixed the problem with DMD. So that's it. There are unknown random internal factors that prevent CTFE or CTFE-type optimisation. I had wondered if pointers might present a problem. The function in question originally was specced something like pure nothrow @nogc @safe void pure_compute( result_t * p_result, in input_t x ) and just as a test, I tried changing it to result_t pure_compute( in input_t x ) instead. I don't think it makes any difference though. I discovered the DMD -void thing at that point so this was not checked out properly. Your enum tip was very helpful. Ps GDC errors: Another thing that has wasted a load of time is that GDC signals errors on lines where there is a function call that is fine, yet the only problem is in the body of the function that is _being_ called itself, and fixing the function makes the phantom error at the call-site go away. This nasty behaviour has you looking for errors at and before the call-site, or thinking you have the spec of the call args wrong or incorrect types. [Compiler-Explorer problem : I am perhaps blaming GDC unfairly, because I have only ever used it through the telescope that is d.godbolt.org and I am assuming that reports errors on the correct source lines. It doesn't show error message text tho, which is a nightmare, but nothing to do with the compiler obviously.]
Re: No CTFE of function
On Sunday, 27 August 2017 at 17:36:54 UTC, Cecil Ward wrote: On Sunday, 27 August 2017 at 00:20:47 UTC, ag0aep6g wrote: [...] Static had already been tried. Failed. Thanks to your tip, I tried enum next. Failed as well, wouldn't compile with GDC. [...] I wonder if there is anything written up anywhere about what kinds of things are blockers to either CTFE or to successful constant-folding optimisation in particular compilers or in general? Would be useful to know what to stay away from if you really need to make sure that horrendously slow code does not get run at runtime. Sometimes it is possible or even relatively easy to reorganise things and do without certain practices in order to win such a massive reward.
Re: No CTFE of function
On Sunday, 27 August 2017 at 00:08:45 UTC, Jonathan M Davis wrote: [...] Indeed. I used the term CTFE too loosely.
Re: No CTFE of function
On Monday, 28 August 2017 at 03:16:24 UTC, Mike Parker wrote: On Sunday, 27 August 2017 at 17:47:54 UTC, Cecil Ward wrote: [...] The rules for CTFE are outlined in the docs [1]. What is described there is all there is to it. If those criteria are not met, the function cannot be executed at compile time. More importantly, as mentioned earlier in the thread, CTFE will only occur if a function *must* be executed at compile time, i.e. it is in a context where the result of the function is required at compile-time. An enum declaration is such a situation, a variable initialization is not. [...] Those links are extremely useful. Many thanks. Because I am full of NHS pain drugs, I am pretty confused half the time, and so finding documentation is difficult for me through the haze, so much appreciated. RTFM of course applies as always.
Re: No CTFE of function
On Saturday, 26 August 2017 at 16:52:36 UTC, Cecil Ward wrote: I have a pure function that has constant inputs, known at compile-time, contains no funny stuff internally - looked at the generated code, and no RTL calls at all. But in a test call with constant literal values (arrays initialised to literal) passed to the pure routine GDC refuses to CTFE the whole thing, as I would expect it (based on previous experience with d and GDC) to simply generate a trivial function that puts out a block of CTFE-evaluated constant data corresponding to the input. Unfortunately it's a bit too long to post in here. I've tried lots of variations. Function is marked nogc safe pure nothrow Any ideas as to why GDC might just refuse to do CTFE on compile-time-known inputs in a truly pure situation? Haven't tried DMD yet. Can try LDC. Am using d.godbolt.org to look at the result, as I don't have a machine here to run a d compiler on. Other things I can think of. Contains function-in-a-function calls, which are all unlined out in the generated code nicely, and not the first time I've done that with GDC either. Switches: Am using -Os or -O2 or -O3 - tried all. Tuning to presume + enable the latest x86-64 instructions. release build, no bounds-checks. I will henceforth use the enum trick advice all times. I noticed that the problem with init =void is compiler-dependent. Using an enum for real CTFE, I don't get error messages from LDC or GDC (i.e. [old?] versions currently up on d.godbolt.org) x64 compilers even if I do use the =void optimisation. This saved a totally wasteful and pointless zero-fill of 64 bytes using 2 YMM instructions in the particular unit test case I had, but of course could easily be dramatically bad news depending on the array size I am unnecessarily filling.
Re: Output range with custom string type
On Monday, 28 August 2017 at 14:27:19 UTC, Jacob Carlborg wrote: I'm working on some code that sanitizes and converts values of different types to strings. I thought it would be a good idea to wrap the sanitized string in a struct to have some type safety. Ideally it should not be possible to create this type without going through the sanitizing functions. The problem I have is that I would like these functions to push up the allocation decision to the caller. Internally these functions use formattedWrite. I thought the natural design would be that the sanitize functions take an output range and pass that to formattedWrite. Here's a really simple example: import std.stdio : writeln; struct Range { void put(char c) { writeln(c); } } void sanitize(OutputRange)(string value, OutputRange range) { import std.format : formattedWrite; range.formattedWrite!"'%s'"(value); } void main() { Range range; sanitize("foo", range); } The problem now is that the data is passed one char at the time to the range. Meaning that if the user implements a custom output range, the user is in full control of the data. It will now be very easy for the user to make a mistake or manipulate the data on purpose. Making the whole idea of the sanitized type pointless. Any suggestions how to fix this or a better idea? Q is it an option to let the caller provide all the storage in an oversized fixed-length buffer? You could add a second helper function to compute and return a suitable safely pessimistic ott max value for the length reqd which could be called once beforehand to establish the reqd buffer size (or check it). This is the technique I am using right now. My sizing function is ridiculously fast as I am lucky in the particular use-case.
General performance tip about possibly using the GC or not
I am vacillating - considering breaking a lifetime's C habits and letting the D garbage collector make life wonderful by just cleaning up after me and ruining my future C disciple by not deleting stuff myself. I don't know when the GC actually gets a chance to run. I am wondering if deleting the usual bothersome immediately-executed hand-written cleanup code could actually improve performance in a sense in some situations. If the cleanup is done later by the GC, then this might be done when the processor would otherwise be waiting for io, in the top loop of an app, say? And if so this would amount to moving the code to be run effectively like 'low priority' app-scheduled activities, when the process would be waiting anyway, so moving cpu cycles to a later time when it doesn't matter. Is this a reasonable picture? If I carry on deleting objects / freeing / cleaning up as I'm used to, without disabling the GC, am I just slowing my code down? Plus (for all I know) the GC will use at least some battery or possibly actually important cpu cycles in scanning and finding nothing to do all the time because I've fully cleaned up. I suppose there might also be a difference in cache-friendliness as cleaning up immediately by hand might be working on hot memory, but the GC scanner coming along much later might have to deal with cold memory, but it may not matter if the activity is app-scheduled like low priority work or is within time periods that are merely eating into io-bound wait periods anyway. I definitely need to read up on this. Have never used a GC language, just decades of C and mountains of asm. Any general guidance on how to optimise cpu usage particularly responsiveness. One pattern I used to use when writing service processes (server apps) is that of deferring compute tasks by using a kind of 'post this action' which adds an entry into a queue, the entry is a function address plus arg list and represents work to be done later. In the top loop, the app then executes these 'posted' jobs later at app-scheduled low priority relative to other activities and all handling of io and timer events, when it has nothing else to do, by simply calling through the function pointer in a post queue entry. So it's a bit like setting a timer for 0 ms, passing a callback function. Terminology - A DFC or lazy, late execution might be other terms. I'm wondering if using the garbage collector well might fit into this familiar pattern? That fair? And actually even help peformance for me if I'm lucky?
Cpu instructions exposed
I have written a few zero-overhead (fully inlining) D wrappers around certain new x64 instructions as an exercise to help me learn D and get used to GDC asm. I've also written D replacements for older processors. They are templated functions with customised variants supporting a variety of different word-widths. 1. Would anyone find these useful? Bet I'm inventing the wheel? (But still a good learning task for me.) 2. How best to get them reviewed for correct D-style and 3. how to package them up, expose them? They need to be usable by the caller in such a was as they get fully directly inlined with no subroutine calls or arg passing adaptation overhead so as to get the desired full 100% performance. For example a call with a literal constant argument should continue to mean an immediate operand in the generated code, which happens nicely currently in my testbeds. So I don't know, the user needs to see the lib fn _source_ or some equivalent GDC cleverness. (Like entire thing in a .h file. Yes, I know, I know. :-) ) 4. I would like to do the same for LDC, unfortunately the asm system is rather different from GDC. I don't know if there is anything clever I can do to try to avoid duplication of effort / totally split sources and double maintenance? (Desperation? Preprocess the D sources with an external tool if all else fails! Yuck. Don't have one at hand right now anyway.) Is there any way I could get D to actually generate some D code to help with that? I have seen some pretty mind-blowing stuff in D using mixin or something - looks fantastic, just like the power of our old friends the evil unconstrained C macros that can generate random garbage C source text without limit, but in D it's done right so the D source can actually be parsed properly, no two languages fighting. I recall using this kind of source generation for dealing with lots of different operator-overloading routines that all follow a similar pattern. Can't think where else. I don't know what is available and what the limits of various techniques are. I'm wondering if I could get D to internally generate GDC-specific or LDC-specific source code strings - the two asm frameworks are syntactically different iirc - starting from a friendly generic neutral format, transforming it somehow. (If memory serves, I think GDC uses a non-D extended syntax, very close to asm seen in GCC for C, for easier partial re-use of snippets from C sources. On the other hand LDC looks more like standard D with complex template expansion, but I haven't studied it properly.) Any general tips to point me in the right direction, much appreciated.
DIPs - question about mores, etiquette and DIP1009 in particular
Is there a way I can simply register my vote eg about DIP 1009? My vote is 'no thanks'. Like the existing system, don't care about the alleged verbosity / room thing, and please whatever do not deprecate the existing syntax because I use it all over the place and the blocks can have complex code in them using statements and multiple statements.
Re: DIPs - question about mores, etiquette and DIP1009 in particular
On Wednesday, 30 August 2017 at 17:19:52 UTC, ketmar wrote: it is explicitly stated in DIP that existing syntax will not be deprecated/removed. i guess that reading the DIP before expressing your opinion is the prerequisite... Good to know. A relief. I am full of pain drugs and missed the no-deprecation thing when I inadequately skimmed the proposal. RTFM as always applies. :-)
Re: DIPs - question about mores, etiquette and DIP1009 in particular
On Wednesday, 30 August 2017 at 22:09:21 UTC, Mike Parker wrote: On Wednesday, 30 August 2017 at 17:16:11 UTC, Cecil Ward wrote: DIPs are not voted on. Thanks for letting me know, answers my question. Our leaders would perhaps find a simple pair of numbers to be a useful additional metric? Demand level, or the opposite, isn't always that obvious, unless you are Professor X.
Address of data that is static, be it shared or tls or __gshared or immutable on o/s
If someone has some static data somewhere, be it in tls or marked shared __gshared or immutable or combinations (whatever), and someone takes the address of it and pass that address to some other routine of mine that does not have access to the source code of the original definition of the object in question, then is it possible to just use 'the address' passed without knowing anything about that data? I'm assuming that the answer might also depend on compilers, machine architectures and operating systems? If this kind of assumption is very ill-advised, is there anything written up about implementation details in different operating systems / compilers ?
Re: Address of data that is static, be it shared or tls or __gshared or immutable on o/s
On Wednesday, 6 September 2017 at 15:55:35 UTC, Ali Çehreli wrote: On 09/06/2017 08:27 AM, Cecil Ward wrote: > If someone has some static data somewhere, be it in tls or marked shared > __gshared or immutable or combinations (whatever), and someone takes the > address of it and pass that address to some other routine of mine that > does not have access to the source code of the original definition of > the object in question, then is it possible to just use 'the address' > passed without knowing anything about that data? I'm assuming that the > answer might also depend on compilers, machine architectures and > operating systems? > > If this kind of assumption is very ill-advised, is there anything > written up about implementation details in different operating systems / > compilers ? Yes, they are all valid operations. Further, the object need not be a static one; you can do the same with any object even it's on the stack. However, - The object must remain alive whenever the other routine uses it. This precludes the case of the object being on the stack and the other routine saving it for later use. When that later use happens, there is no object any more. (An exception: The object may be kept alive by a closure; so even that case is valid.) - Remember that in D data is thread-local by default; e.g. a module variable will appear to be on the same address to all threads but each thread will have its own copy. So, if the data is going to be used in another thread, it must be defined as 'shared'. Otherwise, although the code will look like it's working, different threads will be accessing different data. (Sometimes this is exactly what is desired but not what you're looking for.) (Fortunately, many high-level thread operations like the ones in std.concurrency will not let you share data unless it's 'shared'.) Ali Ali, I have worked on operating systems' development in r+d. My definitions of terms are hopefully the same as yours. If we refer to two threads, if they both belong to the same process, then they share a common address space, by my definition of the terms 'thread' and 'process'. I use thread to mean basically a stack, plus register set, a cpu execution context, but has nothing to do with virtual memory spaces or o/s ownership of resources, the one exception being a tls space, which by definition is one-per-thread. A process is one or more threads plus an address space and a set of all the resources owned by the process according to the o/s. I'm just saying this so you know how I'm used to approving this. Tls could I suppose either be dealt with by having allocated regions within a common address space that are all visible to one another. Objects inside a tls could (1) be referenced by absolute virtual addresses that are meaningful to all the threads in the process, but not meaningful to (threads belong to) other processes. (By definition of 'process'.) or (2) be referenced most often by section-offsets, relative addresses from the start of a tls section, which constantly have to be made usable by having the tls base virtual address added to them before they can be dereferenced adding a big runtime cost and making tls very bad news. I have worked on a system like (2). But even in (2) an address of a type-2 tls object can still be converted to a readily usable absolute virtual address and used by any thread in the process with zero overhead. A third option though could be to use processor segmentation, so tls objects have to (3a) be dereferenced using a segment prefixed operation, and then it's impossible to just have a single dereference operation such as star without knowing whether to use the segment prefix or not. But if it is again possible to use forbidden or official knowledge to convert the segmented form into a process-wide meaningful straight address (as in 8086 20-bit addresses) then we could term this 3a addressing. If this is not possible because vm hardware translation is in use then I will term this 3b. In 3a I am going to assume that vm hardware is used merely to provide relocation, address offsetting, so the use of a segmentation prefix basically merely adds a per-thread fixed offset to the virtual address and if you could discover that offset then you don't need to bother with the segment prefix. In 3b, vm hardware maps virtual addresses to a set of per-tls pages using who-knows-what mechanism, anyway something that apps cannot just bypass using forbidden knowledge to generate a single process-wide virtual address. This means that 3b threads are probably breaking my definition of thread vs process, although they threads of one process do also have a common address space and they share resources. I don't know what d's assumptions if any are. I have very briefly looked at some code generated by GDC and LDC for Linux x64. It seems to me that these are 3a systems, optimised strongly enough by the compilers to
Compiler magic for preventing memory access re-ordering _by the compiler_ (keywords: memory model, compiler optimisations, memory order)
I have to apologise in advance for a truly dumb question, so please be kind. Is there a magic visible sign (or even one needed) in the D language that tells D _compilers_ not to move certain types of memory load / store operations forwards or backwards relative to other operations when optimising the code so that the order in the actual generated code varies from the source code order? I see the various routines available in the runtime library that can generate various sorts of special instructions on CPU x, hardware fences/barriers etc. That's not what I'm asking about tho. I'm just wondering about how the compilers know how much freedom they are allowed in moving stuff forwards/backwards or even deleting stupid wasteful memory operations altogether, and whether there are any special things that a compiler writer needs to spot as being magic in D source code. If the answer is 'no'/'none', I suppose it could be in part down to the fact that the _implementation_ of certain D features by compilers make use of various compiler-specific non-D magic facilities that a compiler already has anyway due to its modern C-implementation heritage? But I don't feel that I've answered my question in this way, if a compiler is generally free to re-order certain statements or external calls past other external calls or special statements. That's a general statement of my ignorance about the limits of compilers’ freedom in optimising code, and something I urgently need to correct. :-) A completely general question, which I should have found an answer to first. (Again, please be nice to a poor fool.) This could be a non-question for all I know, so do forgive my ignorance. If calls to certain types of _routines_ whose content is not know can not be re-ordered either simply (a) because their effects are unknown, or (b) because 'volatile' type declarations are used in the implementation, is that merely how things happen to work? One further dumb question relating to this: if this is meaningful and the answer is case (a) could inlining stuff copied out of the runtime library into your own routines then wreck the safety, and could LTO-type highly clever whole-program optimisation undo safety similarly?
Returning constant / literal struct value (pod)
Can we return a literal struct value straight from a return statement ? ie something like mystruct_t myfunc() { // ... blah return { field1: val1, field2: val2; }; } assuming that the return type is defined suitably, and the struct is just a C struct, plain-old-data (ie not a C++-like class). I've had to set up a throwaway const item, initialised, and then had to return that.
Function argument that is a pointer to memory which the function is not allowed to modify, as in C const
say in C I have a function with a pointer argument foo( const sometype_t * p ) I have asked about this D nightmare before. Using the same pattern in D or the in argument qualifier as far as I can see the value of the pointer is then itself effectively locked made constant. Without dangerous and ugly casts you are stuck. q1. If you want a pointer to memory that is not to be modified then you can't walk the pointer through that memory. So what are my options? I need a pointer that I can increment. (I could avoid the whole issue by using an index instead, but that seems to be giving in to madness.) It seems to me that this is the worst thing I have seen about D. Perhaps trying to make pointers unusable is a surreptious strategt]y for encouraging designers to phase them out. Making code unsafe just to get out of this nightmare (by casting or giving up and dropping important const protection) is not the way. q2. If you want a pointer to modifiable memory but wish to ensure that the value of that address stays fixed, stays where it's put, then what on earth do you do. What are my options? Is there any way at all to campaign for a change to this craziness? I doubt this is a democracy. It's also rather more than a bit late. q3. The in keyword seems to be mixed up concerning the distinction between modifiable arguments and modifiable memory. Is there any way of making in usable for the purposes of documenting the calling convention, showin which arguments are inputs only, which are outputs and which are modified - read-modified-returned? Apologies for my lack for my lack of familiarity with the possible ways out of this. q4. If my understanding is correct, it seems difficult to create a non const copy of (an address that is fixed) either; that is, making a modifiable copy of an address, one which can be incremented, moved upwards starting from a locked base address. It seems that declaring a pointer argument with const or even using the keyword in triggers this problem, the latter being particularly nightmarish because I would want in to mean that that argument (the address, which is what I am declaring) is merely an input-only parameter to the routine, or alternatively a locked /fixed address value which stay s put, and nothing. I'm interested in the cleanest safest techniques for digging myself out of this while always preserving const correctness, preventing possibility of writing to memory and preventing evil type changes where pointers end up pointing to some different kind of objects because if evil casting. I really don't want to use casts that have to much power, where they could allow overrides to any kind of bugs in or even create a new bug, including cases when things break because of duplication of types so later changes of types cause a bug because kludge contain duplicate type specifiers that do not get updated. There probably is a tool somewhere to safely create a modifiable object based on a const object but I'm not sure where to look. Any wise guidance appreciated mucky.
Networking library
Can anyone point me in the direction of a library that provides very very lightweight (minimum overhead) asynchronous i/o routines for - shopping list 1. sending and receiving IPv4 / IPv6 packets, 2. sending receiving ICMP and 3, handling incoming outgoing TCP connections and 4. handling SCTP connections. Secondingly I am in the market for a library that handles the sending and receiving of straight ethernet packets. Also doing ARP / NDP too. Rules of the beauty contest: Some abstraction of asynchronous i/o with asynchronous events, but the main priority is being very very lean and low-level, with top time-performance. If it comes to a beauty contest, this judge I would prefer something C-style as I don't speak C++, have yet to drink the mindless class bullshit koolaid. Since my background is VAX/VMS asynchronous io an asynchronous model with optional callbacks as in VMS or Win NT events will win the beauty parade. Operating systems? Cross-o/s portability- unsure. Not interested in solutions that are synchronous-io-only and so require your code to be split up into multiple threads just to get around the problems caused by synchronous (‘blocking’ some call it) io calls. Requiring threads is a rule-out / show stopper unless I could easily hide such a thing, but that doesn't sound feasible. Any suggestions gratefully received.
Re: Networking library
On Thursday, 15 March 2018 at 00:06:49 UTC, Cecil Ward wrote: Can anyone point me in the direction of a library that provides very very lightweight (minimum overhead) asynchronous i/o routines for - shopping list [...] Actually I realise that if I could simply write a wrapper pretty easily, with suitable help, then C libraries could be included in the list of candidates, but only if I can get the necessary help in writing a D-toC & C-to-D safe wafer-thin wrapper layer.
Re: Function argument that is a pointer to memory which the function is not allowed to modify, as in C const
On Wednesday, 14 March 2018 at 22:23:47 UTC, Cecil Ward wrote: say in C I have a function with a pointer argument foo( const sometype_t * p ) [...] That's the secret - I didn't know about the const (T) * thing - I would never have discovered that ! Many thanks, the missing piece to the puzzle. Many generous replies, thanks to all for their extremely helpful contributions. There is a wealth of precious explanation in them, and apologies for not thanking the contributors individually.
Re: Efficient way to pass struct as parameter
On Tuesday, 2 January 2018 at 18:21:13 UTC, Tim Hsu wrote: I am creating Vector3 structure. I use struct to avoid GC. However, struct will be copied when passed as parameter to function struct Ray { Vector3f origin; Vector3f dir; @nogc @system this(Vector3f *origin, Vector3f *dir) { this.origin = *origin; this.dir = *dir; } } How can I pass struct more efficiently? This isn't a question for you. it's a question for the compiler, let the compiler do its thing. Stick in a -O3 if you are using GCC or LDC and build in release more not debug mode. Make sure that the compiler can see the source code of the implementation of the constructor wherever it is used and it should just be inclined away to nonexistence. Your constructor should not even exist, if it is then you are looking at a false picture or a mistake where optimisation has been turned off for the sake of easy source-level debugging. Post up the assembler language output for a routine where this code is used in some critical situation, and then we can help make sure that the code _generation_ is optimal. I reiterate, unless something is badly wrong or you are seeing a red herring, no 'call' to the constructor code should even exist in the cases where it is actually 'called'. You may well see a useless copy of the constructor code because the compilers seem to generate such even though it is never called ans so is a waste of space. The compiler will analyse the constructor's instructions and just copy-and-paste them as assignment statements with that then getting thoroughly optimised down into something which may just be a memory write or a register-register copy that costs zero. If you post up snippets of generated asm then U will be delighted to take a look.
Re: Efficient way to pass struct as parameter
On Thursday, 15 March 2018 at 23:14:14 UTC, Cecil Ward wrote: On Tuesday, 2 January 2018 at 18:21:13 UTC, Tim Hsu wrote: [...] U or even 'I' will be delighted to take a look.
Re: Efficient way to pass struct as parameter
On Thursday, 15 March 2018 at 23:15:47 UTC, Cecil Ward wrote: On Thursday, 15 March 2018 at 23:14:14 UTC, Cecil Ward wrote: On Tuesday, 2 January 2018 at 18:21:13 UTC, Tim Hsu wrote: [...] U or even 'I' will be delighted to take a look. Also link time optimisation and whole program optimisation might be your friends if you are having problems because module boundaries mean that the compiler cannot expand the source code of the constructor implementation to inline it and fully optimise it away to nothing. You certainly should have no problems if the code that uses the struct can see the struct definition's actual source text directly.
remote execute program
I am wanting to write a short program (on a ‘server’ you could say) that takes a command, runs it (as on the command line, so an executable with arguments or a shell command) and returns a 3-tuple with an int for the return code, plus the textual outputs that it generates to stdout and stderr. I can see a number of suitable routines in the D runtime libraries, which are already D-ified to save me a some trouble mindlessly converting code from C. Where I could do with some help is as follows: I'm needing to send the commands to a remote box using http has to be used because the local-end program (on an iPad) that I have to interfacing to can only speak http/https, and can not handle just a straight eg TCP connection. Despite the overheads from using http, if I can employ gzip compression on the link then that will be a big gain. Could anyone give me some general pointers for where to look? The server box is a linux machine. I'm a very experienced professional C programmer but amazingly have never done anything with *nix in general or http-related C libraries. I asked a question in this forum earlier about general low-level networking, but now this requirement has come up that mandates the use of very simple http and needs only synchronous operations. The impressive framework that is vibe.d has already been mentioned, but the amount of reading matter is rather daunting. A simple D example of an http transaction would be very helpful.
Re: remote execute program
On Friday, 23 March 2018 at 07:57:33 UTC, Kagamin wrote: You can just read the whole request into a buffer and parse it there. Agreed.
Re: remote execute program
On Friday, 23 March 2018 at 01:23:56 UTC, Cecil Ward wrote: I am wanting to write a short program (on a ‘server’ you could say) that takes a command, runs it (as on the command line, so an executable with arguments or a shell command) and returns a 3-tuple with an int for the return code, plus the textual outputs that it generates to stdout and stderr. I can see a number of suitable routines in the D runtime libraries, which are already D-ified to save me a some trouble mindlessly converting code from C. Where I could do with some help is as follows: I'm needing to send the commands to a remote box using http has to be used because the local-end program (on an iPad) that I have to interfacing to can only speak http/https, and can not handle just a straight eg TCP connection. Despite the overheads from using http, if I can employ gzip compression on the link then that will be a big gain. Could anyone give me some general pointers for where to look? The server box is a linux machine. I'm a very experienced professional C programmer but amazingly have never done anything with *nix in general or http-related C libraries. I asked a question in this forum earlier about general low-level networking, but now this requirement has come up that mandates the use of very simple http and needs only synchronous operations. The impressive framework that is vibe.d has already been mentioned, but the amount of reading matter is rather daunting. A simple D example of an http transaction would be very helpful. It's not really a D question, in a sense, it's just that I am out of my depth. And wrapping fat C libraries, particularly converting .h files is something that I don't have any experience of, so something ready-cooked in D would b good. What library routines are available - or do I have to start wading through the vastness of vibe.d?
Link-time optimisation (LTO)
Say that I use say GDC or LDC. I want to declare a routine as public in one compilation unit (.d src file) and be able to access it from other compilation units. Do I simply declare the routine with the word keyword public before the usual declaration? Or maybe that is the default, like not using the keyword static with function declarations in C? My principal question: If I successfully do this, with GCC or LDC, will I be able to get the code for the externally defined short routine expanded inline and fully integrated into the generated code that corresponds to the calling source code? (So no ‘call’ instruction is even found.)
Alignment of struct containing SIMD field - GDC
struct vec_struct { alias field this; bool b; int8 field; } In this code when you look at the generated x64 code output by GDC it seems to be doing a nice job, because it has got the offset right for the 256-bit YMM 'field' correct. Does D automatically propagate the alignment restrictions on the field to the allocation of static structs or structs on the stack? In this case: struct vec_struct { bool b2; struct { alias field this; bool b; int8 field; } } it appears that the offset to 'field' is no longer aligned correctly - offset is 40 bytes in GDC. I don't suppose the compiler will use solely unaligned instructions? In any event, I could take the address of field and then pass that to someone expecting to pick up something with guaranteed correct alignment, if I have understood the D docs. Please don't bite. I'm both new to D and I hope I have understood the x86 SIMD instructions' docs. (Very experienced professional asm and C programmer, but v out-of-date.) Noob q: I notice that the GDC opcodes look a bit odd, for example the compiler generates a 256-bit unaligned fetch followed by an aligned binary operation (I think), eg a movdqu followed by a vpaddd r, ymm ptr blah - is the latter aligned-only? Apologies if I have got this wrong, need to read up. Would someone sanity-check me?
Re: Alignment of struct containing SIMD field - GDC
On Wednesday, 1 March 2017 at 22:15:59 UTC, Iain Buclaw wrote: On Wednesday, 1 March 2017 at 19:09:24 UTC, Johan Engelen wrote: On Wednesday, 1 March 2017 at 18:34:16 UTC, Iain Buclaw wrote: Simple test case would be: struct vec_struct { bool b2; struct { bool b; int8 field; } } static assert(vec_struct.b.offsetof == 32); static assert(vec_struct.field.offsetof == 64); With explicit align(32), it works: https://godbolt.org/g/3GjOHW - Johan Well obviously, because it adheres to explicit alignment. The compiler just has the wrong idea of how default alignment should work. Raised bug here, and I'm raising a PR now also. https://issues.dlang.org/show_bug.cgi?id=17237 Thanks for your help Iain. And many thanks btw for all the general good work which is very much appreciated by this particular geriatric asm programmer. I checked the case of XMM alignment, and it's fine. I presume D does not yet support 512-bit zmm vector objects? (I have seen GDC doing a nice job generating auto-vectorised AVX512 code though - thanks.) The same bug would presumably bite again in that case otherwise?
Re: Alignment of struct containing SIMD field - GDC
On Wednesday, 1 March 2017 at 22:15:59 UTC, Iain Buclaw wrote: On Wednesday, 1 March 2017 at 19:09:24 UTC, Johan Engelen wrote: On Wednesday, 1 March 2017 at 18:34:16 UTC, Iain Buclaw wrote: Simple test case would be: struct vec_struct { bool b2; struct { bool b; int8 field; } } static assert(vec_struct.b.offsetof == 32); static assert(vec_struct.field.offsetof == 64); With explicit align(32), it works: https://godbolt.org/g/3GjOHW - Johan Well obviously, because it adheres to explicit alignment. The compiler just has the wrong idea of how default alignment should work. Raised bug here, and I'm raising a PR now also. https://issues.dlang.org/show_bug.cgi?id=17237 In a dream world where engineers have nothing better to do, it would of course be better to effectively delete the inner anonymous struct so that the two bools could be packed together adjacently. I presume that that is theoretically ok? In contrast, if the sub-struct were named, you could presumably take the address of the entire sub-struct, so the space-inefficient offset to it is something you are just stuck with of course. A noob question: is it illegal to reorder the fields in a struct? (e.g. so as to optimise packing as far as correct alignment allows) - (C compatibility? Would perhaps need to be an _option_?)
Re: Alignment of struct containing SIMD field - GDC
On Wednesday, 1 March 2017 at 22:15:59 UTC, Iain Buclaw wrote: On Wednesday, 1 March 2017 at 19:09:24 UTC, Johan Engelen wrote: On Wednesday, 1 March 2017 at 18:34:16 UTC, Iain Buclaw wrote: Simple test case would be: struct vec_struct { bool b2; struct { bool b; int8 field; } } static assert(vec_struct.b.offsetof == 32); static assert(vec_struct.field.offsetof == 64); With explicit align(32), it works: https://godbolt.org/g/3GjOHW - Johan Well obviously, because it adheres to explicit alignment. The compiler just has the wrong idea of how default alignment should work. Raised bug here, and I'm raising a PR now also. https://issues.dlang.org/show_bug.cgi?id=17237 Iain, this of course is present in my version of LDC too. (I checked.) You couldn't poke David Nadlinger or whoever for me?
Calling a C function whose name is a D reserved word or keyword
Is there a special mechanism in D for handling this problem, where an existing C function might be a name that is reserved in D? Of course I could write a wrapper function in C and call that.
Re: Calling a C function whose name is a D reserved word or keyword
On Monday, 6 July 2020 at 23:40:23 UTC, rikki cattermole wrote: https://dlang.org/spec/pragma.html#mangle pragma(mangle, "body") extern(C) void body_func(); Thanks, that’s excellent
Question about publishing a useful function I have written
I have written something which may or may not be novel and I’m wondering about how to distribute it to as many users as possible, hoping others will find it useful. What’s the best way to publish a D routine ? It is called void assume( bool condition ) nothrow nogc safe for example: assume( x < 100 ); or assume( y != 0 ); It generates no code at all, but t does tell the gdc compiler that the given condition is true and so later code generation may assume that truth in all code generation. So for example, given the assumes above, if ( x==200) is false and no code is generated for the if-true basic block. It might look a bit like assert but it isn’t the same thing. I think assert is disabled in full release build and is only there in debug mode, is that correct? Also assert generates code in that it calls panic or hits a ud2 or whatever, whereas assume is also zero code. Does anyone know if this has already been published by someone else? Unfortunately at the moment it only works with gdc as it relies on functions that are gdc-specific for its implementation. However I could use conditional compilation to simply set up a null implementation for other compilers. I’d like to get it implemented with ldc if I can. If anyone would like to give assume a try with gdc, then shout and I’ll try and find some way of getting it to you easily.
Re: Question about publishing a useful function I have written
On Tuesday, 14 July 2020 at 23:10:28 UTC, Max Haughton wrote: On Tuesday, 14 July 2020 at 21:58:49 UTC, Cecil Ward wrote: I have written something which may or may not be novel and I’m wondering about how to distribute it to as many users as possible, hoping others will find it useful. What’s the best way to publish a D routine ? [...] GitHub is the best place to publish code. Does GDC actually use the optimization? I tried something like that before but I couldn't seem to get it to work properly. On Tuesday, 14 ] I just tried an experiment. It seems that in release mode assert()s are realised as absolutely nothing at all, and so the _conditions_ in the asserts are not declared. So later generated code does not have the benefit of knowledge of asserted truth conditions in release mode. So in release mode, without these truth conditions being established, the code generated (apart from the asserts’ code) can be _worse than in debug mode_, which seems bizarre, but it’s true. for example assert( x < 100 ); … if ( x==200 ) // <— evaluates to false _at compile time_ { // no code generated for this block in debug mode, // but is generated in release mode } … if ( x < 100 ) // <— no code generated for if-test as cond == true at compile-time
Re: Question about publishing a useful function I have written
On Wednesday, 15 July 2020 at 02:25:42 UTC, 9il wrote: On Tuesday, 14 July 2020 at 21:58:49 UTC, Cecil Ward wrote: Does anyone know if this has already been published by someone else? https://github.com/libmir/mir-core/blob/master/source/mir/utility.d#L29 We test LDC and DMC. CI needs an update to be actually tested with GDC. Brilliant. Many thanks.
Forcing inline functions (again) - groan
I recently noticed pragma(inline, true) which looks extremely useful. A couple of questions : 1. Is this cross-compiler compatible? 2. Can I declare a function in one module and have it _inlined_ in another module at the call site? I’m looking to write functions that expand to approx one or even zero machine instructions and having the overhead of a function call would be disastrous; in some cases would make it pointless having the function due to the slowdown.
Templates and SIMD - examining types
I am using SIMD and I have a case in a template where I am being passed an argument that is a pointer to a 128-bit chunk of either 16 bytes or 8 uwords but I don’t know which? What’s the best way to discover this at compile time - using the ‘is’ operator ? I forget for the moment. It will only ever be either a ubyte16 or a ushort8 (if those are the correct type names)? I’ll exclude other possibilities with an if qualifier on the template (somehow). I need to then work out what is the size of the internal units within the 128-bit value, size in bytes,1 or 2, at compile time.
Re: Templates and SIMD - examining types
On Wednesday, 22 July 2020 at 22:21:47 UTC, Dennis wrote: On Wednesday, 22 July 2020 at 21:58:16 UTC, Cecil Ward wrote: I need to then work out what is the size of the internal units within the 128-bit value, size in bytes,1 or 2, at compile time. You can use the .sizeof property on the type. ``` import core.simd; void main() { ubyte16 a; ushort8 b; pragma(msg, a.sizeof); pragma(msg, b.sizeof); pragma(msg, a[0].sizeof); pragma(msg, b[0].sizeof); pragma(msg, typeof(a[0])); pragma(msg, typeof(b[0])); } ``` 16LU 16LU 1LU 2LU ubyte ushort Brilliant. I am sooo stupid, I forgot you can access SIMD variables like normal arrays. Thank you for waking me up again :-)
Strong typing and physical units
I found an earlier post somewhere about work someone has done on physical units such as kg, volts and so forth. It would be very good to catch bugs such as volts_t v = input_current; But that isn’t nearly enough. With strong typing where we can create arbitrary subtypes that are chosen to be incompatible because they are semantically incompatible in assignment, equality, addition and various other operations, we can catch a lot more bugs. point1.x = point2.y; the above is illegal but we need a way to get the underlying value so we can handle rotation by angle of 90 deg or whatever. These two variables have the same units; their unit is pixels but they cond have a real SI physical unit of length in metres say. Even when they are of the same physical units type they need to be made incompatible to prevent y coordinates from getting mixed up with x coordinates by mistake. also point1.x = width; // illegal and point1.x = height; // even worse Arbitrary sub typing would help here but would need accompanying tools to make it usable, the ‘get underlying value’ thing mentioned earlier might not be the only one, I’m not sure. Any thoughts ? — I tried to do something with wrapping a double say in a (templated) struct with just one field value_ in it and an alias value_ this; but as a miserable D learner, I soon got lost. for some reason when using alias this as above, I can do assignments to my struct, but I cannot initialise it using the alias this simplification mechanism. I’m not sure why. I’m assuming I need an appropriate trivial constructor but why doesn’t this get sorted out for you automatically when you’re using alias this? That would seem to be logical, no? Asking for too much - greedy :-) Cecil Ward.
Lack of asm volatile qualifier (explicitly) again.
I read recently that all asm in D is regarded as ‘volatile’ in the GCC sense, which I take to mean that it is assume to potentially have side effects, and so cannot be optimised away to nothing by the compiler despite the lack of any outputs. I would like to be able to either use the asm volatile qualifier now and have it do absolutely nothing or else have an alternative way of expressing the licence for optimisation allowed by the designer. If it is now way too late to declare that suddenly the _lack_ of volatile means that the compiler can go optimisation-crazy, then we need some alternative ‘is_optimisable’ keyword. Even if we think that we need an ‘is-optimisable’ qualifier, then I would still like to be able to include the asm volatile qualifier or similar just to document the designer’s intent in cases where we genuinely do have a non-obvious side effect in the asm. What do others think? If others agree, how could a very small DIP be set in motion ? That would mean just adding one or two new keywords for the asm qualifier(s), which do precisely nothing at present. If GCC and LDC were willing to start optimising at some point then it would be a matter of doing what the sibling C compilers do with volatile and non-volatile.
Re: Strong typing and physical units
On Tuesday, 28 July 2020 at 07:16:53 UTC, Petar Kirov [ZombineDev] wrote: On Tuesday, 28 July 2020 at 04:40:33 UTC, Cecil Ward wrote: [snip] By the way, I found 2 implementations of unit of measurement in D: https://code.dlang.org/packages/units-d https://code.dlang.org/packages/quantities Thank you Peter! Very helpful. Do you guys have any thoughts also about the strong typing idea?
Re: Strong typing and physical units
Of course, in C I used to do something like strong typing with an opaque type achieved by using something like typedef struct _something {} * type1; and then I had to do casting to get back the real type, which was unchecked but it did prevent the user from mixing up the types type1 and type2 say as they weren’t assignment compatible. I would really like strong typing to be a built in feature. Would anyone else support this?
Re: Strong typing and physical units
I just remembered: another favourite bug of mine would be mixing up indices, using an index with the wrong array, an index to a different array entirely. they’re all just a nightmare load of meaningless ints or uints or hopefully size_t’s.
Re: Lack of asm volatile qualifier (explicitly) again.
On Thursday, 30 July 2020 at 07:05:39 UTC, Iain Buclaw wrote: On Tuesday, 28 July 2020 at 06:57:36 UTC, Cecil Ward wrote: I read recently that all asm in D is regarded as ‘volatile’ in the GCC sense, which I take to mean that it is assume to potentially have side effects, and so cannot be optimised away to nothing by the compiler despite the lack of any outputs. I would like to be able to either use the asm volatile qualifier now and have it do absolutely nothing or else have an alternative way of expressing the licence for optimisation allowed by the designer. If it is now way too late to declare that suddenly the _lack_ of volatile means that the compiler can go optimisation-crazy, then we need some alternative ‘is_optimisable’ keyword. Until recently the absence of the pure keyword implied volatile in gdc. I do plan to re-add it, either only in release mode, or when warnings are added for the following: --- asm pure { "get flags" : "=r" (x); } assert(x == 1); asm { "set flags" : : "r" (x + 1); } asm pure { "get flags" : "=r" (x); } assert(x == 2); --- The second 'get flags' would be removed if optimizing as it is both identical to the first statement, and not clear to the compiler that there is a dependency between the setter and getter statements. Just highlighting one example that might be surprising if you weren't thinking that optimizing mean that as well. Ah. I wasn’t thinking about pure, although I do use it everywhere I can as a matter of course. The absence of something doesn’t hit you in the eye as an expression of the programmer’s intent I suppose, absence of pure just could mean the author forgot to put it in. I see your point though. The value of volatile I saw as in documentation.
Re: Lack of asm volatile qualifier (explicitly) again.
On Saturday, 1 August 2020 at 19:23:00 UTC, Iain Buclaw wrote: On Saturday, 1 August 2020 at 02:36:41 UTC, Cecil Ward wrote: On Thursday, 30 July 2020 at 07:05:39 UTC, Iain Buclaw wrote: [...] Ah. I wasn’t thinking about pure, although I do use it everywhere I can as a matter of course. The absence of something doesn’t hit you in the eye as an expression of the programmer’s intent I suppose, absence of pure just could mean the author forgot to put it in. I see your point though. The value of volatile I saw as in documentation. When the baseline for asm is volatile, I don't think it's entirely surprising to consider pure as a cancellation of that - afterall, if it truly is side-effect free, then it's fine for the compiler to remove the statement block. We are in agreement.
Question about UDAs
When practically speaking would you use UDAs? A real-world use-case? I’ve seen them in use already for core language features instead of keywords like "pure", and I suppose this choice keeps the number of keywords down and the result is perhaps easier to extend. The motivation for these usages is clear but I don’t understand how I might use them in my own code. Ali Çehreli’s book mentions them briefly with an example but that doesn’t seem to qualify as a realistic use-case.
Types of lambda args
In a lambda, how do we know what types the arguments are? In something like (x) => x * x - there I just don’t get it at all. Can you write (uint x) => x * x I’m lost. Cecil Ward.
Re: Types of lambda args
On Monday, 17 August 2020 at 04:30:08 UTC, H. S. Teoh wrote: On Mon, Aug 17, 2020 at 12:20:24AM +, Cecil Ward via Digitalmars-d-learn wrote: In a lambda, how do we know what types the arguments are? In something like (x) => x * x It's implemented as a template, whose argument types are inferred based on usage context. - there I just don’t get it at all. Can you write (uint x) => x * x Of course you can. I’m lost. [...] If you're ever unsure of what the inferred type(s) are, you can do replace the lambda with something like this: (x) { pragma(msg, typeof(x)); return x*x } which will print out the inferred type when the compiler instantiates the lambda. T Ah! That’s the vital missing piece - I didn’t realise it was like a template - I just thought it was an ordinary plain anonymous function, not a generic. All makes sense now.
Named parameters in function call
I can’t remember, do Ada or Modula2 have something like myfunc( x => 100, y => 200, color => blue )[1] which has named parameters that can be passed in any order. Does D have anything like this? If not, would anyone support a development like the above [1] ? If D does not have this, I am wondering about how to write such a thing but the cure might very very easily be worse than the disease. I have little clue here. I have seen a hack for C (written by RevK) that involves assignments to fields in a struct and the struct is then passed to a function. Something like myfunc( { field2: 20, field1: 10, fieldstr : "a string" } ) [2] and preprocessor trickery was used to get rid of the unsightly { } by making a macro call to a wrapper macro that takes variadic ... arguments.
Re: Named parameters in function call
On Tuesday, 8 September 2020 at 09:40:11 UTC, Andre Pany wrote: On Tuesday, 8 September 2020 at 07:43:05 UTC, Cecil Ward wrote: I can’t remember, do Ada or Modula2 have something like myfunc( x => 100, y => 200, color => blue )[1] which has named parameters that can be passed in any order. [...] I hope we have it this year or next year, as we have this DIP https://www.github.com/dlang/DIPs/tree/master/DIPs%2FDIP1030.md Kind regards Andre I wonder if there is any way in which we could combine this with strong typing of some sort (how?) to detect errors such as int xcoord; int ycoord; myfunc( x : ycoord, y : xcoord, color : blue )[3] where the arguments are the wrong way around. Would have to change the types of the xcoord and ycoord variables somehow, something I have asked about earlier.
Range checked assignment
What I would like to do is (in pseudo-code) : declare_var my_var : int range 0..7; // i.e. 0 <= val <= 7; my_var = 6; // ok my_var = 8; // bang ! static assert fail or assert fail at runtime my_var = 6; my_var += 2; // bang ! value 8 is > 7 So every assignment is range-checked at either compile-time if at all possible or else at runtime. This includes things like += and initialisers of course, not just straight assignment. I assumed I would have to create a struct type definition and handle various operators. How many will I have to handle? I would of course make it a template so I can reuse this otherwise horribly repetitive code.
Re: Range checked assignment
On Tuesday, 8 September 2020 at 16:04:29 UTC, Harry Gillanders wrote: On Tuesday, 8 September 2020 at 14:18:14 UTC, Cecil Ward wrote: [...] If you want to define an integral-like type which is more-or-less interchangeable with the native integral types, you'll need to provide the following overloads and members: [...] Harry, thank you indeed for your generous help. Much appreciated.
Re: Named parameters in function call
On Wednesday, 9 September 2020 at 11:48:28 UTC, Paul Backus wrote: On Tuesday, 8 September 2020 at 13:28:22 UTC, Cecil Ward wrote: I wonder if there is any way in which we could combine this with strong typing of some sort (how?) to detect errors such as int xcoord; int ycoord; myfunc( x : ycoord, y : xcoord, color : blue )[3] where the arguments are the wrong way around. Would have to change the types of the xcoord and ycoord variables somehow, something I have asked about earlier. import std.typecons: Typedef; alias XCoord = Typedef!(int, int.init, "XCoord"); alias YCoord = Typedef!(int, int.init, "YCoord"); auto myfunc(XCoord x, YCoord y) { ... } Brilliant. Thank you Paul.
enum and const or immutable ‘variable’ whose value is known at compile time
A really stupid question, I fear. If I have some kind of declaration of some ‘variable’ whose value is strictly known at compile time and I do one of the following (rough syntax) either enum foo = bar; or const foo = bar; or immutable foo = bar; then is there any downside to just using enum all the time? - I don’t need to take the address of foo, in fact want to discourage &foo, (as I said, given that I can do so) Is there any upside either to using enum? I’m a bit nervous about using immutable having had bad allergic reactions when passing immutable ‘variables’ to functions and so just tend to use const or enum.
Re: enum and const or immutable ‘variable’ whose value is known at compile time
On Wednesday, 16 September 2020 at 17:19:13 UTC, Adam D. Ruppe wrote: On Wednesday, 16 September 2020 at 17:12:47 UTC, Cecil Ward wrote: then is there any downside to just using enum all the time? For a non-string array, enum may give runtime allocations that static immutable won't. Generally think of enum as being replaced with the literal representation and array literals actually make a new array. This may or may not matter to you. So can the result of declaring certain things with enum ever have an _address_ then? (According to legit D code that is, never mind the underlying implementation details, which may not be observable) I actually really hate the way enum was bent out of shape and twisted from its original purpose so that finally we end up with a way of defining only one value, not the whole range of permissible values for a type as in the beginning. I wish there were just a keyword ‘constant’ or something (yes, I know, you could just call that something ‘enum’, or ‘const’)
Re: enum and const or immutable ‘variable’ whose value is known at compile time
On Thursday, 17 September 2020 at 01:57:39 UTC, Mike Parker wrote: On Thursday, 17 September 2020 at 00:32:40 UTC, Cecil Ward So can the result of declaring certain things with enum ever have an _address_ then? (According to legit D code that is, never mind the underlying implementation details, which may not be observable) No. Think of it as a named literal. Thank you Mike. That’s exactly what I thought. And it’s another reason in favour of using enum - that it forbids address-taking and so declares that there will be none.
New to GDC on ARM 32-bit Ubuntu
I am getting an error when I try and compile anything with the GDC compiler which is coming up associated with source code within a D include file which is not one of mine I am using a Raspberry Pi with Ubuntu 16.04 and have just done an "apt-get install gdc". Using ldc works fine. The error is : root@raspberrypi:~# gdc mac_hex.d -O3 -frelease /usr/include/d/core/stdc/config.d:58:3: error: static if conditional cannot be at global scope static if( (void*).sizeof > int.sizeof ) ^ This file has == version(Windows) ... else version( Posix ) { static if( (void*).sizeof > int.sizeof ) { etc etc == It shows version gdc --version gdc (Ubuntu/Linaro 5.3.1-14ubuntu2) 5.3.1 20160413 Copyright (C) 2015 Free Software Foundation, Inc. So that is unfortunately really old and I would love to get a new package
write a function template specialisation that tests if an argument is known at compile time
T myfunc(T)( T x, uint mask ) if ( mask == 3 ) { return fast_func( x, mask ); } but of course this doesn't work because mask is not known at compile-time. so I wondered if there is a way to do something like static if ( isKnownAtCompileTime( mask ) ) but that would not necessarily help me and probably isn't the right way. Basically there is a fast path for certain known values of a (second in this case) argument where the compiler could produce superb trivial code or where I can work out a shortcut myself. for example myfunc( x, 0 ) == 0 and myfunc( x, -1 ) == x and various other good things, and for some values of mask the thing behaves like an AND operation so I want the compiler to just generate that. The default slow path where the arg is unknown involves calling asm so the compiler cannot use its intelligence as it does not know the detailed semantics. Also: To add further complication: if both arguments of myfunc() are known at compile-time, then I definitely want to take an alternative path because then I can apply CTFE and calculate a compile-time result.
Re: write a function template specialisation that tests if an argument is known at compile time
On Saturday, 11 August 2018 at 05:17:51 UTC, Cecil Ward wrote: T myfunc(T)( T x, uint mask ) if ( mask == 3 ) { return fast_func( x, mask ); } but of course this doesn't work because mask is not known at compile-time. Actually is there an opportunity for some kind of language enhancement there? I do not really know what I am talking about AT ALL but if the compiler could silently add an extra specialisation that gets generated at compile time, with constant folding and all the optimisations that follow from it, if a call with an appropriate constant argument is seen? But this is probably horrible because that kind of stuff is ph performed at a completely different point ?
Re: write a function template specialisation that tests if an argument is known at compile time
On Saturday, 11 August 2018 at 18:11:15 UTC, Paul Backus wrote: On Saturday, 11 August 2018 at 05:17:51 UTC, Cecil Ward wrote: T myfunc(T)( T x, uint mask ) if ( mask == 3 ) { return fast_func( x, mask ); } but of course this doesn't work because mask is not known at compile-time. so I wondered if there is a way to do something like static if ( isKnownAtCompileTime( mask ) ) but that would not necessarily help me and probably isn't the right way. You can create an overload where `mask` is passed as a template parameter: T myfunc(uint mask, T)(T x) { static if(mask == 3) { return fast_func(x, mask); } else { return func(x, mask); } } The same technique is used by `std.format.format` in the standard library to pass a format string that's known at compile time. Paul, what would the calls look like? I am about to misunderstand things completely so here goes :-) It would be a bit kludgy having to switch from one calling syntax to another, putting the mask argument in the template parameters or in the normal position. Or have I misunderstood? And if the caller did not use the right call syntax variant then the optimisation would not happen. Thing is, as it is the details are nicely hidden and the caller does not even need to thing about the fact that an (eponymous) template is being used.
Re: write a function template specialisation that tests if an argument is known at compile time
On Sunday, 12 August 2018 at 00:55:50 UTC, Paul Backus wrote: On Sunday, 12 August 2018 at 00:15:37 UTC, Cecil Ward wrote: Paul, what would the calls look like? I am about to misunderstand things completely so here goes :-) It would be a bit kludgy having to switch from one calling syntax to another, putting the mask argument in the template parameters or in the normal position. Or have I misunderstood? And if the caller did not use the right call syntax variant then the optimisation would not happen. Thing is, as it is the details are nicely hidden and the caller does not even need to thing about the fact that an (eponymous) template is being used. As far as I know, there's no way to *guarantee* the optimization and keep the normal function call syntax. Probably the best you can do is write the mask check as a regular if statement, put `pragma(inline, true)` in the function, and hope the optimizer is smart enough to get rid of the branch. I was thinking about reflection and powerful things like traits. Would a test to see if a static if compile do the trick ? You ask the question using traits : "does the following compile? : { static if ( mask == 3 ) { }; }" - any use?
Re: write a function template specialisation that tests if an argument is known at compile time
On Sunday, 12 August 2018 at 02:17:21 UTC, Cecil Ward wrote: On Sunday, 12 August 2018 at 00:55:50 UTC, Paul Backus wrote: On Sunday, 12 August 2018 at 00:15:37 UTC, Cecil Ward wrote: Paul, what would the calls look like? I am about to misunderstand things completely so here goes :-) It would be a bit kludgy having to switch from one calling syntax to another, putting the mask argument in the template parameters or in the normal position. Or have I misunderstood? And if the caller did not use the right call syntax variant then the optimisation would not happen. Thing is, as it is the details are nicely hidden and the caller does not even need to thing about the fact that an (eponymous) template is being used. As far as I know, there's no way to *guarantee* the optimization and keep the normal function call syntax. Probably the best you can do is write the mask check as a regular if statement, put `pragma(inline, true)` in the function, and hope the optimizer is smart enough to get rid of the branch. I was thinking about reflection and powerful things like traits. Would a test to see if a static if compile do the trick ? You ask the question using traits : "does the following compile? : { static if ( mask == 3 ) { }; }" - any use? I am out of my depth but I am also wondering about using mixin in some way, conditionally. And the kind of thing I am also thinking about is something like if this ( xxx ) compiles then xxx // put in the code under a conditional compilation if else pull in alternative code and all the ifs are compile time. so zero run time penalty which absolutely essential in my case because in fact the bodies are just single instructions and it is a choice between a cheaper instruction ( or no instruction at all ) and a 3-4 times more costly instruction, but an if statement is 50 times more expensive because of branch misprediction risk as well as the cost of the test itself
Re: write a function template specialisation that tests if an argument is known at compile time
On Sunday, 12 August 2018 at 12:27:59 UTC, Alex wrote: On Saturday, 11 August 2018 at 05:17:51 UTC, Cecil Ward wrote: T myfunc(T)( T x, uint mask ) if ( mask == 3 ) { return fast_func( x, mask ); } [...] Is it the volcano pattern you are looking for? https://p0nce.github.io/d-idioms/#Is-this-available-at-compile-time-or-runtime? Wow, now that _is_ clever. I think that is definitely a big part of it. Now somehow after having used a static if to select the known-at-compile-time case I then have to test the argument for particular values. So how to get the next step along the way?
Re: write a function template specialisation that tests if an argument is known at compile time
On Tuesday, 14 August 2018 at 02:53:01 UTC, Cecil Ward wrote: On Sunday, 12 August 2018 at 12:27:59 UTC, Alex wrote: On Saturday, 11 August 2018 at 05:17:51 UTC, Cecil Ward wrote: T myfunc(T)( T x, uint mask ) if ( mask == 3 ) { return fast_func( x, mask ); } [...] Is it the volcano pattern you are looking for? https://p0nce.github.io/d-idioms/#Is-this-available-at-compile-time-or-runtime? Wow, now that _is_ clever. I think that is definitely a big part of it. Now somehow after having used a static if to select the known-at-compile-time case I then have to test the argument for particular values. So how to get the next step along the way? Would it be ok to ask Walter maybe ? I am so far out of my depth here tho.
Getting rid of const/immutable
I have a particular type name and that type may or may not be const and/or immutable. How do I make a new type based on this that is mutable, ie getting rid of both const and immutable, but not knowing what the original type is ? I don’t want to repeat information from the definition of the original type as this would introduce a bug if the original definition is later changed. Something like alias immutable_cash_t = immutable(float); alias mutable_cash_t = float; // better, in case the original were ever to be changed from ‘float’ to ‘real’ some day alias mutable_cash_t = GetRidOfImmutable!( GetRidOfConst!( mutable_cash_t ) );
Writing a dejargoniser - producing read ke analysis output in English that explains GDC / LDC asm code’s parameters and clobbers
How much code do you thing I would need to write for this? I’m still thinking about its feasibility. I don’t want to invent the wheel and write a custom parser by hand, so’d rather steal the code using sim eg called ‘a library’. :-) The idea would be that the user could run this to sanity-check her understanding of the sometimes arcane GDC asm code outputs/inputs/clobbers syntax, and see what her asm code’s constraints are actually going to do rather than what she thinks it’s going to do. Clearly I can’t readily start parsing the asm body itself, I would just inspect the meta info. (If that’s the right word?) I would have a huge problem with LDC’s alternative syntax unless I could think of some way to pre-transform and munge it into GDC format. I do wish LDC (and DMD) would now converge on the GDC asm syntax. Do you think that’s reasonably doable?
Re: std.socket tutorials? examples?
On Saturday, 29 April 2023 at 11:26:20 UTC, Adam D Ruppe wrote: On Saturday, 29 April 2023 at 10:56:46 UTC, Jan Allersma wrote: auto clientResult = Socket.select(clientSet, null, null); There's probably nothing in clientSet, so it is waiting for nothing you almost always want to have just one call to select in the program, not two, the whole point is to combine checks. I wrote a thing you might want to read too: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_11_11.html#sockets-tutorial How do we wait for an ‘or’ of multiple asynchronous events in this kind of code? In WinNT iirc there is a very nice o/s function that can wait on various kinds of asynch i/o, waiting on operations of different types if I’ve understood it correctly. The kind of thing I might want to do is wait on an or of IP packets arriving, send-completion of IP packets, timers completing, IPC messages coming in, key presses or event mouse events and the order in which these events arrive is of course not predictable. I might want a key press event to break out of something or to control an application. Everyone wants timer events for timeouts.
Re: std.socket tutorials? examples?
On Sunday, 30 April 2023 at 22:37:48 UTC, Adam D Ruppe wrote: On Sunday, 30 April 2023 at 22:10:31 UTC, Cecil Ward wrote: How do we wait for an ‘or’ of multiple asynchronous events in this kind of code? You can set a timeout value for Socket.select, but Phobos isn't going to help you with anything other than sockets and timeouts (despite the fact the underlying operating systems can, in fact, do it). There's a few other libs that can help with this, including one I'm aiming to release some time in May, or vibe.d has its own ways of doing it, among others. You can also import core.sys.stuff and call the OS functions without a middle man. But the D stdlib is quite underpowered when it comes to these things. Socket.select is ok but just the basics. Many thanks, Adam.
Re: quick question, probably of little importance...
On Wednesday, 26 April 2023 at 23:07:39 UTC, WhatMeWorry wrote: On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew Cattermole wrote: Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing. Thanks. Fastest reply ever! And I believe across the world? I suppose my examples required overhead of a function call. So maybe num % 2 == 0 is fastest? I made a small change, making the retval a bool rather than an int. I got slightly better code generation with the int, as it seems that some of the compilers have not yet got all the good tricks they should be using when manipulating bool-typed expressions and also it can be one extra instruction converting values to bool strictly zero or one, not zero or any non-zero value. Here’s the D, enlarged a little so that we can see your routine in action, inlined. Your isEven boils down to two instructions with a seriously optimising compiler. I’ve included the x86-64 machine code generated by the GDC and LDC compilers so you can see how fast it is. GDC made a bit of a dog’s breakfast of my longer routine whereas LDC performed superbly. GDC generated twice as much code, but its excellent instruction scheduler and what looks like an awareness of ILP mean that the two streams of instructions will be carried out in parallel so the two streams will only take three instruction times - ie whatever the total time is for those three instruction in the one stream - not six. bool isEven( int num ) { return ! ( num & 1 ); } bool AreBothEven( int a, int b ) // returns true if both arguments are even { return isEven( a ) && isEven( b ); } === Compiler output:: GDC:: x86-64: -O3 -mcpu=native -frelease bool isEven( int ): mov eax, edi not eax and eax, 1 ret bool AreBothEven( int, int ): mov eax, edi not esi not eax and esi, 1 and eax, 1 cmovne eax, esi ret === Compiler LDC: x86-64: -O3 -mcpu=native -release bool isEven( int ): testdil, 1 seteal ret bool AreBothEven( int, int ): or edi, esi testdil, 1 seteal ret
Re: quick question, probably of little importance...
On Monday, 1 May 2023 at 03:53:24 UTC, Cecil Ward wrote: On Wednesday, 26 April 2023 at 23:07:39 UTC, WhatMeWorry wrote: [...] Correction: I can’t count. There are only two instructions in parallel with another pair running alongside, not three. The first reg, reg move counts as zero cycles, so the total time is just the sum of the following three instructions’ times, ignoring the other parallel stream.
Code duplication where you wish to have a routine called with either immutable or mutable arguments
I have often come into difficulties where I wish to have one routine that can be called with either immutable or (possibly) mutable argument values. The argument(s) in question are in, readonly, passed by value or passed by const reference. Anyway, no one is trying to write to the items passed in as args, no badness attempted. When I call the routine from one place with an argument that is immutable and then from another that is not, or it could be const as well, or not, that’s when I get all kinds of type mismatch errors. And I certainly don’t want to pour cast-like type conversion operations over all the place at these problem occurrences. it’s surely asking for problems. Could I make the one routine into a template? Even if I did, that would perhaps create additionally problems, since even if it all worked and instantiated either immutable or mutable forms of the routine, what happens if I have two args and they have a mixture of immutable and no immutable args ? So nargs * 2 ( or more) possibilities? I’m out of my depth here.
Re: Code duplication where you wish to have a routine called with either immutable or mutable arguments
On Tuesday, 30 May 2023 at 04:15:22 UTC, Ali Çehreli wrote: On 5/29/23 19:57, Cecil Ward wrote: > I wish to have one routine > that can be called with either immutable or (possibly) mutable argument > values. 'const' should take both immutable and mutable. Can you show your case with a short example? > Could I make the one routine into a template? That could work but give 'in' parameters a try: https://dlang.org/spec/function.html#in-params Ali T2 foo( in T1 x ) { return bar( x ) }; It was with something vaguely like the above that I had to remove the in (templatised generic function possibly) in order to get it to compile with GDC or LDC on godbolt.org (or d.godbolt.org) latest versions available. -O3 -release/-frelease -march=native/-mcpu-native
Re: Code duplication where you wish to have a routine called with either immutable or mutable arguments
On Wednesday, 31 May 2023 at 03:23:01 UTC, Cecil Ward wrote: On Tuesday, 30 May 2023 at 04:15:22 UTC, Ali Çehreli wrote: On 5/29/23 19:57, Cecil Ward wrote: > I wish to have one routine > that can be called with either immutable or (possibly) mutable argument > values. 'const' should take both immutable and mutable. Can you show your case with a short example? > Could I make the one routine into a template? That could work but give 'in' parameters a try: https://dlang.org/spec/function.html#in-params Ali T2 foo( in T1 x ) { return bar( x ) }; It was with something vaguely like the above that I had to remove the in (templatised generic function possibly) in order to get it to compile with GDC or LDC on godbolt.org (or d.godbolt.org) latest versions available. -O3 -release/-frelease -march=native/-mcpu-native I have to admit that I don’t really understand immutable. I have an idea that it could mean that an object has an address in ROM, so its value will never change. Maybe const doesn’t give you such a strong guarantee, disallows ‘you’ from modifying it but others might do so, but who knows. Without a guarantee as strong as the first idea I can’t really understand how const can work properly. "You treat it as const so do not modify it, but it might not be eternally fixed and unchanging" that doesn’t seem to have enough value to me. But maybe I’ve got the whole thing wrong. In an architecture where you have strongly typed (tagged ? segmented?) different kinds of addresses, I can see why you might be getting type mismatch errors when passing addresses around.
Re: Code duplication where you wish to have a routine called with either immutable or mutable arguments
On Wednesday, 31 May 2023 at 09:14:49 UTC, Dom DiSc wrote: On Wednesday, 31 May 2023 at 03:29:33 UTC, Cecil Ward wrote: I have to admit that I don’t really understand immutable. I have an idea that it could mean that an object has an address in ROM, so its value will never change. Maybe const doesn’t give you such a strong guarantee, disallows ‘you’ from modifying it but others might do so, but who knows. There are two perspectives: that of the value handed to a function and that of the function taking the value. "immutable" (or "mutable") is a property of the value, "const" is a property of the function. If the function can work with mutable values, but in fact doesn't mutate them itself, it could also work with immutable values. The fact that others could modify your "const" value doesn't matter for immutable values, because they of course can't be modified by others. For the function it doesn't matter, because it only guarantees not to modify it itself, don't care about what other can or can't do. Without a guarantee as strong as the first idea I can’t really understand how const can work properly. "You treat it as const so do not modify it, but it might not be eternally fixed and unchanging" that doesn’t seem to have enough value to me. Why? What guarantee are you missing? Your function can work with mutable data, so you don't care if it can be modified also by others. Now it happens that you doesn't modify the data. So why shouldn't you be able to work on data that guarantees that it also will not be changed by others? You don't care for such modification anyway. The meaning of "immutable" is: I cannot be modified. Not by you and not by anybody else. It's a property of a value. The meaning of "mutable" is: I can be modified by anybody. Work with me only if that is ok for you. It's a property of a value. The meaning of "const" is: I don't care if others modify the data or not, I won't modify it myself. It's a property of a function. Dom, you explain it well. I’m just too stupid. Literally, as I’m on strong pain drugs all the time, so things are a bit fuzzy. As a professional C programmer for some years, I understood the word const and used it all the time, as much as possible at every opportunity, so I had some expectations. But the errors I’m getting don’t fit in with the previous understanding I had with the familiar ‘const’ keyword and make me think there must be something else going on. So I will need to capture an example in the wild, cage it and bring it in for scientific examination. I can’t ask for an explanation of things going on that you can’t inspect for yourself, obviously. And I don’t understand what the problem is with using in as much as possible yet having to remove it sometimes when something immutable is in use.
Indenting standards religions K&R, whitesmiths etc
I wanted to ask how some of the leaders of our group feel about D indentation standards. `i realise that this causes some religious fervour in C. I could be in trouble here because in all my years at work, we never used K & R ‘one true brace style’ indenting, with the house style I’m used to being more like whitesmiths. Wikipedia explains this better. Something like the following below. So my question: would I get lynched for the following? (below) And can anyone recommend a beautifier / pretty printer tool for D that is customisable to your house style if that is a thing that’s needed? I assume I would need that if I were to donate code, unless some helpful recipient would run such a tool on .d files received. — pure nothrow etc T foo( T, T2 )( in T param x, in T2 param y ) if ( template-qualification-whatever ) in { static assert( … ); } out ( ret ) { … assert( test ret ); } do { blah if ( test ) { … if-body … } back to main block … … } /* end of function, notice the indent level stays out with the content */
How does D’s ‘import’ work?
Is there an explanation of how D’s ‘import’ works somewhere? I’m trying to understand the comparison with the inclusion of .h files, similarities if any and differences with the process.
Re: Indenting standards religions K&R, whitesmiths etc
On Wednesday, 31 May 2023 at 22:06:50 UTC, Ernesto Castellotti wrote: On Wednesday, 31 May 2023 at 16:24:38 UTC, Cecil Ward wrote: I wanted to ask how some of the leaders of our group feel about D indentation standards. `i realise that this causes some religious fervour in C. I could be in trouble here because in all my years at work, we never used K & R ‘one true brace style’ indenting, with the house style I’m used to being more like whitesmiths. Wikipedia explains this better. Something like the following below. [...] Excuse me but for me the only style I like is the K&R. I can accept Allman but the rest is heretical to me ;-) don't worry, just a joke Is there even such as thing as a pretty-printer / beautifier for D ? Has anyone adapted one ? `it might save me from a lynch mob. :-) :-)
Re: How does D’s ‘import’ work?
On Wednesday, 31 May 2023 at 18:56:02 UTC, H. S. Teoh wrote: On Wed, May 31, 2023 at 06:43:52PM +, Cecil Ward via Digitalmars-d-learn wrote: Is there an explanation of how D’s ‘import’ works somewhere? I’m trying to understand the comparison with the inclusion of .h files, similarities if any and differences with the process. Unlike C's #include, `import` does NOT paste the contents of the imported file into the context of `import`, like #include would do. Instead, it causes the compiler to load and parse the imported file, placing the parsed symbols into a separate symbol table dedicated for that module (in D, a file == a module). These symbols are then pulled into the local symbol table so that they become available to code containing the import declaration. (There's a variation, `static import`, that does the same thing except the last step of pulling symbols into the local symbol table. So the symbols will not "pollute" the current namespace, but are still accessible via their fully-qualified name (FQN), i.e., by the form `pkg.mod.mysymbol`, for a symbol `mysymbol` defined in the module `pkg.mod`, which in turn is a module under the package `pkg`.) For more information: https://tour.dlang.org/tour/en/basics/imports-and-modules https://dlang.org/spec/module.html T Thank you so very much for the links and for your generous help. Some C compilers used to have a thing called ‘precompiled headers’, potential source of trouble and ai always felt uneasy about it rightly or wrongly. It’s great that D has got rid of header file includes though, they were ridiculously painful. I used to use the automake feature that was built into the JPI C compiler at work which took care of all the .h dependencies so you no longer had to worry about it. And you only loaded the compiler from disk and started it up once as it stayed in memory handling all the C parts of a make.
Re: How does D’s ‘import’ work?
On Wednesday, 31 May 2023 at 18:43:52 UTC, Cecil Ward wrote: Is there an explanation of how D’s ‘import’ works somewhere? I’m trying to understand the comparison with the inclusion of .h files, similarities if any and differences with the process. I have another question if I may, what do we do about getting makefiles right given that we have imports ?
Re: Indenting standards religions K&R, whitesmiths etc
On Thursday, 1 June 2023 at 09:37:43 UTC, Dukc wrote: On Wednesday, 31 May 2023 at 16:24:38 UTC, Cecil Ward wrote: I wanted to ask how some of the leaders of our group feel about D indentation standards. `i realise that this causes some religious fervour in C. I could be in trouble here because in all my years at work, we never used K & R ‘one true brace style’ indenting, with the house style I’m used to being more like whitesmiths. Wikipedia explains this better. Something like the following below. So my question: would I get lynched for the following? (below) Check out this module from me: https://github.com/dukc/nuklearbrowser/blob/master/source/nuklearbrowser.d Plus similar style in most of my posts and bug reports. I'm still alive :D. Your code is your code. There, you may do as you wish. You have to aknowledge that an esoteric style may make it more difficult to read for some, but we're not lynching people for other factors of code readability either. Brace style is no different. Plus, what brace style is considered readable by the majority is a culture issue. There has to be some way to challege the established culture. If you don't exercise your power to code as you wish, someone will make your choice for you. Coding culture, or even culture in general, cannot develop if people never challege the present status quo. When you're coding with others, though, then you should obey the style guideline of that project if there is one. Even there you're as entitled as anyone for an opinion what the style policy should be (and to whether there should be style policy at all), but you then should (usually) obey the decision regardless whether it's the one you were advocating for. Agree completely. You are not a criminal though because your closing braces are not indented out with the block they’re closing as I do. I find K&R hard to read even though we see it everywhere, or variants of it. I do wonder if my style in that earlier post hurts normal people’s eyeballs a lot. ;-) I’m told that Irish speakers can’t understand Scottish Gaelic on the radio a native speaker said to me that ‘it’s just a noise’. But as a ScG learner myself I can understand some spoken Irish even though I’ve never really studied the modern language (only the stuff of more that 1100 yrs ago.) So the pain isn’t symmetrical.
Re: Indenting standards religions K&R, whitesmiths etc
On Thursday, 1 June 2023 at 09:37:43 UTC, Dukc wrote: On Wednesday, 31 May 2023 at 16:24:38 UTC, Cecil Ward wrote: I wanted to ask how some of the leaders of our group feel about D indentation standards. `i realise that this causes some religious fervour in C. I could be in trouble here because in all my years at work, we never used K & R ‘one true brace style’ indenting, with the house style I’m used to being more like whitesmiths. Wikipedia explains this better. Something like the following below. So my question: would I get lynched for the following? (below) Check out this module from me: https://github.com/dukc/nuklearbrowser/blob/master/source/nuklearbrowser.d Plus similar style in most of my posts and bug reports. I'm still alive :D. Your code is your code. There, you may do as you wish. You have to aknowledge that an esoteric style may make it more difficult to read for some, but we're not lynching people for other factors of code readability either. Brace style is no different. Plus, what brace style is considered readable by the majority is a culture issue. There has to be some way to challege the established culture. If you don't exercise your power to code as you wish, someone will make your choice for you. Coding culture, or even culture in general, cannot develop if people never challege the present status quo. When you're coding with others, though, then you should obey the style guideline of that project if there is one. Even there you're as entitled as anyone for an opinion what the style policy should be (and to whether there should be style policy at all), but you then should (usually) obey the decision regardless whether it's the one you were advocating for. I wonder how much work it would be to write a D pretty printer / beautifier. Doing things such as lining up parameters or comments and breaking and re-wrapping comments etc if necessary because of the changes in whitespace. I’ve no idea what the ‘official story’ is with nested functions. I have some experience with that because I used to write Pascal (on a Z80 box and on a VAX), and that feature is like the return of an old friend, I love it so much and for me it’s quite a serious advantage over C. I’m always guilty of overcommenting, for various reasons although I’m not guilt of the likes of /* add 1 to x */! ;-) It’s partly because I have a shocking memory and maintenance becomes literally impossible for me, for me just as important I want the comments to spell out original intent, not the implementation choices, so if you see later that the two don’t match then you’ve spotted the bug. Many people comment in a very minimal way which makes the code look neat. I did sort of find an /* add 1 to x */ though as it was explaining and giving a caveat about GCC in-line asm constraints, and the comment saved me having to go and look things up in the bible.
Re: How does D’s ‘import’ work?
On Friday, 2 June 2023 at 12:07:09 UTC, rempas wrote: On Thursday, 1 June 2023 at 03:47:00 UTC, Cecil Ward wrote: I have another question if I may, what do we do about getting makefiles right given that we have imports ? What do you mean with that? Give some more info please! I was thinking about the situation in C where I have a rule in a make file that lists the .h files as well as the .c all as dependencies in creating an object file.
Re: byte and short data types use cases
On Friday, 9 June 2023 at 11:24:38 UTC, Murloc wrote: Hi, I was interested why, for example, `byte` and `short` literals do not have their own unique suffixes (like `L` for `long` or `u` for `unsigned int` literals) and found the following explanation: - "I guess short literal is not supported solely due to the fact that anything less than `int` will be "promoted" to `int` during evaluation. `int` has the most natural size. This is called integer promotion in C++." Which raised another question: since objects of types smaller than `int` are promoted to `int` to use integer arithmetic on them anyway, is there any point in using anything of integer type less than `int` other than to limit the range of values that can be assigned to a variable at compile time? Are these data types there because of some historical reasons (maybe `byte` and/or `short` were "natural" for some architectures before)? People say that there is no advantage for using `byte`/`short` type for integer objects over an int for a single variable, however, as they say, this is not true for arrays, where you can save some memory space by using `byte`/`short` instead of `int`. But isn't any further manipulations with these array objects will produce results of type `int` anyway? Don't you have to cast these objects over and over again after manipulating them to write them back into that array or for some other manipulations with these smaller types objects? Or is this only useful if you're storing some array of constants for reading purposes? Some people say that these promoting and casting operations in summary may have an even slower overall effect than simply using int, so I'm kind of confused about the use cases of these data types... (I think that my misunderstanding comes from not knowing how things happen at a slightly lower level of abstractions, like which operations require memory allocation, which do not, etc. Maybe some resource recommendations on that?) Thanks! For me there are two use cases for using byte and short, ubyte and ushort. The first is simply to save memory in a large array or neatly fit into a ‘hole’ in a struct, say next to a bool which is also a byte. If you have four ubyte variables in a struct and then an array of them, then you are getting optimal memory usage. In the x86 for example the casting operations for ubyte to uint use instructions that have zero added cost compared to a normal uint fetch. And casting to a ubyte generates no code at all. So the costs of casting in total are zero. The second use-case is where you need to interface to external specifications that deman uint8_t (ubyte), or uint16_t (ushort) where I am using the standard definitions from std.stdint. These types are the in C. If you are interfacing to externally defined struct in data structures in ram or in messages, that’s one example. The second example is where you need to interface to machine code that has registers or operands of 8-bit or 16-bit types. I like to use the stdint types for the purposes of documentation as it rams home the point that these are truly fixed width types and can not change. (And I do know that in D, unlike C, int, long etc are of defined fixed widths. Since C doesn’t have those guarantees that’s why the C stdint.h is needed in C too.) As well as machine code, we could add other high-level languages where interfaces are defined in the other language and you have to hope that the other language’s type widths don’t change.
Re: byte and short data types use cases
On Friday, 9 June 2023 at 15:07:54 UTC, Murloc wrote: On Friday, 9 June 2023 at 12:56:20 UTC, Cecil Ward wrote: On Friday, 9 June 2023 at 11:24:38 UTC, Murloc wrote: If you have four ubyte variables in a struct and then an array of them, then you are getting optimal memory usage. Is this some kind of property? Where can I read more about this? So you can optimize memory usage by using arrays of things smaller than `int` if these are enough for your purposes, but what about using these instead of single variables, for example as an iterator in a loop, if range of such a data type is enough for me? Is there any advantages on doing that? Read up on ‘structs’ and the ‘align’ attribute in the main d docs, on this website. Using smaller fields in a struct that is in memory saves RAM if there is an array of such structs. Even in the case where there is only one struct, let’s say that you are returning a struct by value from some function. If the struct is fairly small in total, and the compiler is good (ldc or gdc, not dmd - see godbolt.org) then the returned struct can fit into a register sometimes, rather than being placed in RAM, when it is returned to the function’s caller. Yesterday I returned a struct containing four uint32_t fields from a function and it came back to the caller in two 64-bit registers, not in RAM. Clearly using smaller fields if possible might make it possible for the whole struct to be under the size limit for being returned in registers. As for your question about single variables. The answer is very definitely no. Rather, the opposite: always use primary CPU-‘natural’ types, widths that are most natural to the processor in question. 64-bit cpus will sometimes favour 32-bit types an example being x86-64/AMD64, where code handling 32-bit ints generates less code (saves bytes in the code segment) but the speed and number of instructions is the same on such a 64-bit processor where you’re dealing with 32- or 64- bit types. Always use size_t for index variables into arrays or the size of anything in bytes, never int or uint. On a 64-bit machine such as x86-64, size_t is 64-bit, not 32. By using int/uint when you should have used size_t you could in theory get a very rare bug when dealing with eg file sizes or vast amounts of (virtual) memory, say bigger than 2GB (int limit) or 4GB (uint limit) when the 32-bit types overflow. There is also a ptrdiff_t which is 64-bit on a 64-bit cpu, probably not worth bothering with as its raison d’être was historical (early 80s 80286 segmented architecture, before the 32-bit 386 blew it away).
Re: byte and short data types use cases
On Friday, 9 June 2023 at 15:07:54 UTC, Murloc wrote: On Friday, 9 June 2023 at 12:56:20 UTC, Cecil Ward wrote: On Friday, 9 June 2023 at 11:24:38 UTC, Murloc wrote: If you have four ubyte variables in a struct and then an array of them, then you are getting optimal memory usage. Is this some kind of property? Where can I read more about this? So you can optimize memory usage by using arrays of things smaller than `int` if these are enough for your purposes, but what about using these instead of single variables, for example as an iterator in a loop, if range of such a data type is enough for me? Is there any advantages on doing that? A couple of other important use-cases came to me. The first one is unicode which has three main representations, utf-8 which is a stream of bytes each character can be several bytes, utf-16 where a character can be one or rarely two 16-bit words, and utf32 - a stream of 32-bit words, one per character. The simplicity of the latter is a huge deal in speed efficiency, but utf32 takes up almost four times as memory as utf-8 for western european languages like english or french. The four-to-one ratio means that the processor has to pull in four times the amount of memory so that’s a slowdown, but on the other hand it is processing the same amount of characters whichever way you look at it, and in utf8 the cpu is having to parse more bytes than characters unless the text is entirely ASCII-like. The second use-case is about SIMD. Intel and AMD x86 machines have vector arithmetic units that are either 16, 32 or 64 bytes wide depending on how recent the model is. Taking for example a post-2013 Intel Haswell CPU, which has 32-byte wide units, if you choose smaller width data types you can fit more in the vector unit - that’s how it works, and fitting in more integers or floating point numbers of half width means that you can process twice as many in one instruction. On our Haswell that means four doubles or four quad words, or eight 32-bit floats or 32-bit uint32_ts, and similar doubling s’s for uint16_t. So here width economy directly relates to double speed.
Re: byte and short data types use cases
On Saturday, 10 June 2023 at 21:58:12 UTC, Cecil Ward wrote: On Friday, 9 June 2023 at 15:07:54 UTC, Murloc wrote: On Friday, 9 June 2023 at 12:56:20 UTC, Cecil Ward wrote: [...] Is this some kind of property? Where can I read more about this? My last example is comms. Protocol headers need economical narrow data types because of efficiency, it’s all about packing as much user data as possible into each packet and fatter, longer headers reduce the amount of user data as the total has a hard limit on it. A pair of headers totalling 40 bytes in IPv4+TCP takes up nearly 3% of the total length allowed, so that’s a ~3% speed loss, as the headers are just dead weight. So here narrow types help comms speed.
Re: byte and short data types use cases
On Sunday, 11 June 2023 at 00:05:52 UTC, H. S. Teoh wrote: On Sat, Jun 10, 2023 at 09:58:12PM +, Cecil Ward via Digitalmars-d-learn wrote: On Friday, 9 June 2023 at 15:07:54 UTC, [...] On contemporary machines, the CPU is so fast that memory access is a much bigger bottleneck than processing speed. So unless an operation is being run hundreds of thousands of times, you're not likely to notice the difference. OTOH, accessing memory is slow (that's why the memory cache hierarchy exists). So utf8 is actually advantageous here: it fits in a smaller space, so it's faster to fetch from memory; more of it can fit in the CPU cache, so less DRAM roundtrips are needed. Which is faster. Yes you need extra processing because of the variable-width encoding, but it happens mostly inside the CPU, which is fast enough that it generally outstrips the memory roundtrip overhead. So unless you're doing something *really* complex with the utf8 data, it's an overall win in terms of performance. The CPU gets to do what it's good at -- running complex code -- and the memory cache gets to do what it's good at: minimizing the amount of slow DRAM roundtrips. I completely agree with H. S. Teoh. That is exactly what I was going to say. The point is that considerations like this have to be thought through carefully and width of types really does matter in the cases brought up. But outside these cases, as I said earlier, stick to uint, size_t and ulong, or uint32_t and uint64_t if exact size is vital, but do also check out the other std.stdint types too as very occasionally they are needed.