Re: Tuple DIP
On Saturday, 13 January 2018 at 18:28:55 UTC, Timon Gehr wrote: However, this proposal is independent of all the other ones, so in the end it is up to Walter and Andrei. Have there been any discussions regarding the semantics of _? struct G { ~this() { writeln("destruct"); } } void main() { auto _ = G(); writeln("here"); } The DIP currently says this should print first "here" and then "destruct". However, as you cannot access the variable later, you most often want to discard the data right away, i.e. print first "destruct" and then "here". I personally find the second interpretation more useful.
Re: John Regehr on "Use of Assertions"
On Saturday, 1 September 2018 at 20:15:15 UTC, Walter Bright wrote: Note the "may or may not be evaluated." We've debated this here before. I'm rather pleased that John agrees with me on this. I.e. the optimizer can assume the expression is true and use that information to generate better code, even if the assert code generation is turned off. You only read what you want to hear or what? His essay is built up in a way where he shows two opposing interpretations of asserts. Assertions as "bug detectors" or as "optimizer hints". He then discusses which one of those is the better one. The quote you gave is the definition from a proponent of the "optimizer hint" camp and not necessarily what John agrees with. His conclusion in the essay is that in general it makes sense to have assertions enabled even in release builds because a slightly worse performance is worth it to have more robust programs and he has backed this up by a lot of examples. Furthermore, he wrote a follow-up post about "assume" (https://blog.regehr.org/archives/1096). Assume seems to be what you think assert is, but there is actually a *huge* difference. We assert a condition when we believe it to be true in every non-buggy execution of our program, but we want to be notified if this isn’t the case. In contrast, we assume a condition when our belief in its truth is so strong that we don’t care what happens if it is ever false. In other words, while assertions are fundamentally pessimistic, assumptions are optimistic. So no, John doesn't agree with you on this *at all*.
Re: Is there any hope for "lazy" and @nogc?
On Tuesday, 31 July 2018 at 07:49:40 UTC, Shachar Shemesh wrote: On 31/07/18 10:29, Mike Franklin wrote: Please clarify if I'm missing the point. You are. I want something along the lines of: assertEQ(a, b, "a and b are not equal"); When run, it would issue an assert that says: Assertion failed: 3!=7: a and b are not equal What D really needs is power asserts. assertEQ's and its companions (assertLT, assertLE, ...) feel just like hacks. Power asserts come from Groovy and look like this (http://groovy-lang.org/semantics.html#_power_assertion): assert calc(x,y) == [x,z].sum() || | | | | | 15 2 7 | 2 5 7 false A poorer version exists in C++ (https://www.boost.org/doc/libs/1_67_0/libs/test/doc/html/boost_test/testing_tools/boost_test_universal_macro.html) and of course any language with decent metaprogramming facilities can implement them as a library solution (such as Rust: https://github.com/gifnksm/power-assert-rs and Go: https://github.com/ToQoz/gopwt). If you can not go the route of metaprogramming, provide an assert backend (Javascript: https://github.com/power-assert-js/power-assert). D needs something like this as well, and you can not get there just with lazy.
Re: Tuple DIP
On Friday, 12 January 2018 at 22:44:48 UTC, Timon Gehr wrote: foreach((sum, diff); [(1, 2), (4, 3)].map!((a, b) => (a + b, a - b))) { writeln(sum, " ", diff); } I'm not a big fan of the foreach syntax. It's so easy to forget or accidentally add parentheses while coding, or read it wrongly while skimming over the code. Not sure if anything can be done against that, though. Maybe add an alternate "for (.. in ..)" syntax that doesn't have that problem?
Re: Should we add `a * b` for vectors?
On Thursday, 5 October 2017 at 22:04:10 UTC, Jonathan M Davis wrote: It's far cleaner for them to be tied to the type - especially when you consider that it's not possible to differentiate between conflicting overloadeded operators. In other words, we lose global uniqueness of operators if we were to allow free functions to implement operators. Knowing which function is called when we see its name is very important for reading code. That's why we have those anti hijacking rules: they disallow cases where the compiler knows that the call can be misleading (or can silently break existing code). Another, more tricky case is when there are two functions with the same name in the project you are working on, but only one of them is being imported. If you read the code, you are unsure which one is called. The anti-hijacking rules won't work in that case. Fortunately, a good naming scheme avoids those problems so they are not a big problem in practice. Those problems will pop up, however, if we allow them for operators. Without further regulations, different implementations for operators are almost guaranteed, which will lead to uncertainty and distrust in code using operators. Besides, I don't how it should work without changes to lookup rules. How should sum() be able to use a +-operator defined in an imported module? Not even ADL is helping here. In my opinion, operators should only be defined in the module defining the type.
Re: @safe(bool)
On Thursday, 17 August 2017 at 16:32:20 UTC, bitwise wrote: In a high-performance context though, the performance hit may be unacceptable. Well in those super rare situations, there's always the workaround with mixins: mixin template funcWithAttr(string decl, string attributes, string code) { pragma(msg, "<<<" ~ code ~ ">>>"); mixin(decl ~ attributes ~ "{" ~ code ~" }"); } struct Container(T, bool safetyOn = true) { static if(safe) RefCounted!(T[]) data; else T[] data; mixin funcWithAttr!("auto opSlice()", safetyOn ? "@safe" : "", q{ return Range(data, 0, data.length); }); }
Re: @safe(bool)
On Saturday, 19 August 2017 at 16:02:27 UTC, bitwise wrote: We have to consider the potential for abuse. I don't like measuring features on the potential for abuse, but this feature cries for abuse. Even in the simpler form of your proposal. Let's say there are two functions with conditional @safe f(T)(...) @safe(!hasAliasing!T) {...} g(bool B)(...) @safe(B) {...} and we combine them into another function, h(T,bool B) @safe(!hasAliasing!T && B) { f(T)(...); g(B)(...); } then in the correct @safe specification there is an additional clause for every conditionally-safe function. This doesn't scale well. So the guideline would be to use your feature very rarely and only if it's obvious from the meaning of the template arguments; if it gets too complicated, just don't specify it. Which would mean the feature should only be used in few corner cases, and is thus not worth the cost of complicating the language. You already commented on the other usage of dip 1012, the @nice and @naughty attributes. They just don't scale in a similar way. C++ has had the same feature for some time: noexcept(true) means noexcept, noexcept(false) means an exception may be thrown (of course this works with any constant expressions). I just grepped through Boost and I have found 53 uses of noexcept(expression), from 5264 total uses of noexcept (excluding the math library). And Boost is one of those libraries that are overly precise with such things to a degree that the code becomes unreadable. In code outside of Boost and the standard library, noexcept(expression) it is basically unused.
Re: C++17 Init statement for if/switch
On Wednesday, 16 August 2017 at 12:58:03 UTC, Joakim wrote: That is correct. After a while it gets tiring to see a neverending stream of complexity added to the language while things that would actually help (like IDE support) do not get any attention. +1, though I'd go for bug-fixing over IDEs. I like that. Feature freeze D until *all* bug reports are closed. While that would mean no more features for several years, I think it would benefit the language in the long run, both internally (less discussions about incorrect behavior) and externally (D is a mature and stable language).
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 20:15:11 UTC, Timon Gehr wrote: On 16.07.2017 21:49, Guillaume Boucher wrote: On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote: It is therefore most natural to say that Bottom.sizeof == ∞. True, but size_t.max doesn't have the properties of ∞. The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom). In this case, Bottom.sizeof is a value of type Bottom, which must not exist. It doesn't exist during runtime, but there's no problem to just generate assert(0) where it's used. I think my interpretation produces the least exceptions, but if you have a better idea go ahead.
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 20:04:25 UTC, Timon Gehr wrote: The issue isn't purism, it is type safety. If you create an EvolvedPenguin, upcast it to a Penguin and call the fly method you get UB. So noreturn would indeed need to enforce that all overrides are also noreturn. I see it as some kind of weak guarantee, where the compiler can assume noreturn only if he knows there are no subtypes involved (e.g. if he's applying devirtualization). Automatically inheriting the attribute could break existing code (especially if it's inferred).
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote: It is therefore most natural to say that Bottom.sizeof == ∞. True, but size_t.max doesn't have the properties of ∞. The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom).
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 13:03:40 UTC, Timon Gehr wrote: I don't think that's true. A Bottom type does not cover all use cases of @noreturn/@pragma(noreturn). ... I think it does, but it is a significantly more invasive language change. The best you can hope for is that any code with pragma(noreturn) can be rewritten into functionally equivalent code that uses Bottom and gives the same hints to the optimizer. pragma(noreturn) can be inferred implicitly which makes it more impactful in practice. I'd say a function with return type Bottom can override any function in the base class. That solves the "Penguin : Bird" step, but not "EvolvedPenguin : Penguin" (which can fly). Andrei argues that my example don't comply with a puristic understanding of inheritance. Maybe that's enough of a reason to not optimize such use cases, but it still shows that pragma(noreturn) is somehow stronger than Bottom. pragma(noreturn) is indeed the simpler solution, as it does not interact with anything else. The fact that template constraints in some cases need to be aware of the existence of Bottom in order to work for Bottom is clearly a negative property of this solution in the context of D. Yes, basically this. You can return 'auto' instead of U. Then the return type will be inferred either as U or Bottom. Sure there are workarounds. Also here: auto deref(T)(ref T* x) { return deref(*x); } ref T deref(T)(ref T x) if (!isPointer!T) { return x; } But when every small function needs a rewrite, something seems off.
Re: proposed @noreturn attribute
On Monday, 10 July 2017 at 04:02:59 UTC, Nicholas Wilson wrote: 1)@noreturn 2)@disable(return) 3)none w.r.t optimisation assuming both 1 & 3 impact DMD equally [...] I don't think that's true. A Bottom type does not cover all use cases of @noreturn/@pragma(noreturn). Example 1: Polymorphism class Bird { void fly() { ... } }; class Penguin : Bird { override void fly() @pragma(noreturn) { assert(0); } }; class EvolvedPenguin : Penguin { override void fly() { ... } }; There's no way to encode that information in a return type. Example 2: Compile-time polymorphism Same as above, except during compile time. While it looks ok in theory (just return Bottom, and everything is alright), it seems very tricky to get right. Example from checkedint.d: auto r = hook.hookOpUnary!op(payload); return Checked!(typeof(r), Hook)(r); Let's say the hook refuses to perform hookOpUnary, so r is Bottom. Unfortunately, Checked!(Bottom, Hook)(r) doesn't compile (because "if (isIntegral!T || is(T == Checked!(U, H), U, H))" fails). While Bottom may be substituted into all expressions (which doesn't seem easy anyway), it for sure can't be inserted as any template argument. As seen before, Checked is not Bottom-proof. I would think that most templates are not Bottom-proof and making them Bottom-proof seems quite a bit of work. With @pragma(noreturn) that situation would be no problem. Example 3: Unreachable statements/Implicit noreturn inference As pointed out by Steven Schveighoffer, the current unreachability errors should probably be removed in generic code. If we do that, then generic functions can be @pragma(noreturn) if certain conditions are met. A compiler can easily figure that out, but writing it inside static ifs could be almost impossible. Assume we have a hook to Checked that disallows casts. Current signature: U opCast(U, this _)() if (isIntegral!U || isFloatingPoint!U || is(U == bool)) The compiler can figure out that all code paths end with an @pragma(noreturn), so it can add that pragma implicitly to the signature. However, the compiler can't change the return type from U to Bottom (otherwise static equality checks with U will fail).
Re: Checked vs unchecked exceptions
On Monday, 26 June 2017 at 18:42:24 UTC, Ola Fosheim Grøstad wrote: On Monday, 26 June 2017 at 17:44:15 UTC, Guillaume Boucher wrote: Java uses A, Rust/Go use B. C++ uses B to some extend (e.g. in std::experimental::filesystem). The C++17 filesystem api provides two alternatives, the standard filesystem_error exception and an output-paramater for capturing os-specific error codes. I'm not quite sure why they provide both, but I guess performance and the ability to compile for runtimes with exceptions turned off could explain it. Quoting the C++ standard: Filesystem library functions often provide two overloads, one that throws an exception to report file system errors, and another that sets an error_code. [Note: This supports two common use cases: - Uses where file system errors are truly exceptional and indicate a serious failure. Throwing an exception is an appropriate response. - Uses where file system errors are routine and do not necessarily represent failure. Returning an error code is the most appropriate response. This allows application specific error handling, including simply ignoring the error. -- end note] I would say that the overload without exceptions is the "standard" one. It is rather clear though that C++ std lib relies heavily on exceptions. [Citation needed]
Re: Checked vs unchecked exceptions
On Monday, 26 June 2017 at 17:50:47 UTC, Moritz Maxeiner wrote: I have tried using such Monads in D, but in the end it always ended up being too verbose or too hard to read compared to using exceptions or even simple error codes (with 0 == no error). I haven't tried that yet, tbh. visit is nice, but can't always be used. So I guess unless D introduces syntax for pattern matching, it will always be verbose. In that case a reference to an error code would be the most viable design in D.
Re: Checked vs unchecked exceptions
On Monday, 26 June 2017 at 16:52:22 UTC, Sebastien Alaiwan wrote: Checked exceptions allow a lot more precision about what types of exceptions a function can throw. I totally agree that this is a problem with D right now. If you want to catch all errors, how are you supposed to remember what std.file.readText throws? Or std.file.mkdir? There are two solutions to this problem that I know of: A) Checked exceptions B) Error codes that can't be implicitly ignored Java uses A, Rust/Go use B. C++ uses B to some extend (e.g. in std::experimental::filesystem). In my opinion, option B better than A because checked exceptions are incredibly verbose. However, both are better than nothing (which is the current state of D right now). It is very well possible to use option B in D. The most convenient one is making functions nothrow and use Algebraic!(T, ErrorCode), or, for void functions, have a parameter "ref ErrorCode". If all functions in Phobos would either follow that pattern or provide an alternative nothrow overload, I would consider that problem solved.
Re: DIP 1009--Improve Contract Usability--Preliminary Review Round 1
On Sunday, 25 June 2017 at 15:46:12 UTC, Petar Kirov [ZombineDev] wrote: out result > 0 // perhaps the best How would you handle things like this: T minimum(T)(RedBlackTree!T tree) in (!tree.empty) out result in (tree) { return tree.front; } That could either mean "out(result){assert(result in (tree));}" or out(result){assert(result);} in{assert(tree);}"
Re: Makefile experts, unite!
On Sunday, 11 June 2017 at 19:17:36 UTC, Andrei Alexandrescu wrote: Instead of an error, I get a no-op result that looks like success. How can that situation be converted to an error? That makefile target is poorly written. It was probably intended to have a dependency on the directory itself, so by adding "%/" to the pattern it correctly produces an error (since std.algorithm.d doesn't exist): %.test : $(LIB) %/ ... To allow for your case, just add this line: std.%.test : std/%.test While that should work (at least for the first level), it still is very poorly written. It doesn't use the white-listed modules/packages despite the rest of the makefile seems to use that fairly consistently. I would replace all the ".test" targets with the following code: # Target for quickly running a single unittest (using static phobos library). # For example: "make std/algorithm/mutation.test" # The mktemp business is needed so .o files don't clash in concurrent unittesting. $(addsuffix .test,$(D_MODULES)): %.test : %.d $(LIB) T=`mktemp -d /tmp/.dmd-run-test.XX` && \ ( \ $(DMD) -od$$T $(DFLAGS) -main -unittest $(LIB) -defaultlib= -debuglib= $(LINKDL) -cov -run $< ; \ RET=$$? ; rm -rf $$T ; exit $$RET \ ) # Target for quickly unittesting all modules and packages within a package, # transitively. For example: "make std/algorithm.test" define PACKAGETEST_template $(1).test: $$(patsubst %,$(1)/%.test,$$(PACKAGE_$(subst /,_,$(1 endef $(foreach package,$(STD_PACKAGES),$(eval $(call PACKAGETEST_template,$(package # Target for quickly unittesting all modules and packages by using dot as a separator. # For example: "make std.algorithm.sorting.test" define MODULESYNTAXTEST_template $(subst /,.,$(1)).test : $(1).test endef $(foreach module,$(STD_PACKAGES) $(D_MODULES),$(eval $(call MODULESYNTAXTEST_template,$(module (I'm not going to make a pull request though.)
Re: Another "D is cool" post
On Monday, 29 May 2017 at 19:07:03 UTC, H. S. Teoh wrote: So, recently in one of my pet projects I have a bit of code that takes a string, fills in a code template, invokes the D compiler to create a shared object, then loads the object with dlopen() and calls dlsym() to get the entry point into the compiled code as a function pointer. Seems like the perfect job for a scripting language like Python. I'm not sure why you decided to compare everything to C. Even C programmers will agree with you that in D you can do things in a shorter way -- just slower/bloated/more magic/with less control/not portable/. In all the examples you bring, there's nothing special about D. You can do anything in C++/Go/Rust/Swift/Python/language> with comparable complexity. The tricky part, though, is that .mangleof only works on an identifier defined in the *current* program; the compiler can't do it for a symbol in a string that's to be passed at runtime to another invocation of the compiler. And AFAIK, there's currently no way to ask the compiler "what would be the mangling of mymodule.symbol?" if 'mymodule' and 'symbol' only exist in the shared object, not in the main program. Not a problem in any other language (C++ has a well-defined ABI, dynamic languages don't need that). I enjoy D, but some of those fanboy posts are just totally worthless.
Re: Idea: Reverse Type Inference
On Monday, 22 May 2017 at 13:20:41 UTC, Stefan Koch wrote: type inference is not magic, it's a search for a pattern over the syntax (sub)tree. Hence it can have quadratic time/memory complexity. Well, the type system of Scala is turing complete, hence it can take arbitrarily long: https://michid.wordpress.com/2010/01/29/scala-type-level-encoding-of-the-ski-calculus/
Re: Fantastic exchange from DConf
On Sunday, 14 May 2017 at 09:42:05 UTC, Patrick Schluter wrote: But completely removing the code when one encounters for example: if(val+1 == INT_MIN) is simply nuts. Removing such code is precisely what dmd does: https://issues.dlang.org/show_bug.cgi?id=16268
Re: Fantastic exchange from DConf
On Wednesday, 10 May 2017 at 01:19:08 UTC, Nick Sabalausky (Abscissa) wrote: The moral of this story: Sometimes, breaking people's code is GOOD! ;) I don't get the hate that compiler warnings get in the D community. Sure you can disable them if you don't care, but then don't complain about C being inherently unsafe and bug-prone while praising D for breaking things. Uninitialized variables is an example that I think does not need to be a language feature: If the compiler can prove the usage is sound, everything is fine. The compiler has much deeper knowledge about the concrete case than static language rules. If analysis fails, issue a warning. Usually the problematic code is far from obvious and refactoring is a good idea. If the programmer still thinks that no action is needed, just suppress that warning with a pragma.
Re: Fantastic exchange from DConf
On Wednesday, 10 May 2017 at 05:26:11 UTC, H. S. Teoh wrote: int myfunc(blah_t *blah, bleh_t *bleh, bluh_t *bluh) { void *resource1, *resource2, *resource3; int ret = RET_ERROR; /* Vet arguments */ if (!blah || !bleh || !bluh) return ret; /* Acquire resources */ resource1 = acquire_resource(blah->blah); if (!resource1) goto EXIT; resource2 = acquire_resource(bleh->bleh); if (!resource1) goto EXIT; resource3 = acquire_resource(bluh->bluh); if (!resource1) goto EXIT; /* Do actual work */ if (do_step1(blah, resource1) == RET_ERROR) goto EXIT; if (do_step2(blah, resource1) == RET_ERROR) goto EXIT; if (do_step3(blah, resource1) == RET_ERROR) goto EXIT; ret = RET_OK; EXIT: /* Cleanup everything */ if (resource3) release(resource3); if (resource2) release(resource2); if (resource1) release(resource1); return ret; } In modern C and with GLib (which makes use of a gcc/clang extension) you can write this as: gboolean myfunc(blah_t *blah, bleh_t *bleh, bluh_t *bluh) { /* Cleanup everything automatically at the end */ g_autoptr(GResource) resource1 = NULL, resource2 = NULL, resource3 = NULL; gboolean ok; /* Vet arguments */ g_return_if_fail(blah != NULL, FALSE); g_return_if_fail(bleh != NULL, FALSE); g_return_if_fail(bluh != NULL, FALSE); /* Acquire resources */ ok = acquire_resource(resource1, blah->blah); g_return_if_fail(ok, FALSE); ok = acquire_resource(resource2, bleh->bleh); g_return_if_fail(ok, FALSE); ok = acquire_resource(resource3, bluh->bluh); g_return_if_fail(ok, FALSE); /* Do actual work */ ok = do_step1(blah, resource1); g_return_if_fail(ok, FALSE); ok = do_step2(blah, resource1); g_return_if_fail(ok, FALSE); return do_step3(blah, resource1); } Some random example of this style of coding: https://github.com/flatpak/flatpak/blob/master/common/flatpak-db.c
Re: Fantastic exchange from DConf
On Tuesday, 9 May 2017 at 16:55:54 UTC, H. S. Teoh wrote: Ouch. Haha, even I forgot about this particularly lovely aspect of C. Hooray, freely call functions without declaring them, and "obviously" they return int! Why not? To be fair, most of your complaints can be fixed by enabling compiler warnings and by avoiding the use of de-facto-deprecated functions (strnlen). The remaining problems theoretically shouldn't occur by disciplined use of commonly accepted C99 guidelines. But I agree that even then and with the use of sanitizers writing correct C code remains very hard.
Re: Static foreach pull request
On Tuesday, 9 May 2017 at 03:06:37 UTC, Timon Gehr wrote: If you are interested in static foreach making it into the language, please play with the implementation and tell me how to break it. Code: void main() { void f() { idonotexist(); } static foreach(j;0..0) { f(); } } Output: test_staticforeach.d(3): Error: undefined identifier 'idonotexist' Statement::blockExit(0x7f38d5cd35e0) static foreach (j; __error) { f(); } core.exception.AssertError@ddmd/blockexit.d(90): Assertion failure ??:? _d_assertp [0x72e590] ??:? _ZN9blockExit9BlockExit5visitEP9Statement [0x637bd0] ??:? _ZN7Visitor5visitEP22StaticForeachStatement [0x625b45] ??:? _ZN22StaticForeachStatement6acceptEP7Visitor [0x61ebf8] ??:? int ddmd.blockexit.blockExit(ddmd.statement.Statement, ddmd.func.FuncDeclaration, bool) [0x637b69] ??:? _ZN9blockExit9BlockExit5visitEP17CompoundStatement [0x637ef9] ??:? _ZN17CompoundStatement6acceptEP7Visitor [0x61dc61] ??:? int ddmd.blockexit.blockExit(ddmd.statement.Statement, ddmd.func.FuncDeclaration, bool) [0x637b69] ??:? _ZN15FuncDeclaration9semantic3EP5Scope [0x5bba3d] ??:? _ZN6Module9semantic3EP5Scope [0x563f31] ??:? int ddmd.mars.tryMain(ulong, const(char)**) [0x5e2b46] ??:? _Dmain [0x5e3a12] ??:? _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFNlZv [0x7301da] ??:? scope void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x730124] ??:? scope void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll() [0x730196] ??:? scope void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x730124] ??:? _d_run_main [0x7300a2] ??:? main [0x5e411f] ??:? __libc_start_main [0xd4999510]
Re: Making AssertError a singleton
On Monday, 12 December 2016 at 15:51:07 UTC, Andrei Alexandrescu wrote: I think all Errors should be singletons - multiple objects in that hierarchy arguably make no sense. With that logic, why does Throwable have the field "next"?
Re: dmd -Wl=comma_separated_linker_flags (cf clang++ -Wl, comma_separated_linker_flags)
On Sunday, 11 December 2016 at 21:39:26 UTC, Timothee Cour wrote: is there a way to pass linker flags? dmd -Wl=comma_separated_linker_flags eg: dmd -Wl=-lbar,-Ldir,--export-dynamic,-pie (same functionality as clang++ -Wl,-lbar,-Ldir,--export-dynamic,-pie) If not could we support it? Would make a lot of things easier. Just use shell expansions? dmd -Wl,-{lbar,Ldir,-export-dynamic,pie}
Re: Fun: Shooting yourself in the foot in D
On Thursday, 27 October 2016 at 19:59:09 UTC, Steven Schveighoffer wrote: You create a large meta-template library called footMassage, which then ends up via compiler inference compiling into a gun instead. Accidentally compiling a massage into a gun is not a high priority bug. In order to become the safest language available, we should concentrate our effort implementing a nitrogen oxide detector (which handles all non-pathological examples of smoke).
Re: Anyone has time for a unittesting issue?
On Saturday, 1 October 2016 at 19:51:05 UTC, Dicebot wrote: I think that is OK but only if actual file inside the dir is created with `mktemp --tmpdir=/tmp/.dmd-test-run/` (or using a similar technique). This is not sufficient. Any user can create a symlink from /tmp/.dmd-test-run/ to e.g. /very/private/root/directory/ (that user can't access it, but symlinks don't check the permission of the target). Executed as root user, mktemp then creates a unique file in /very/private/root/directory/. Which can be used for example to litter a filesystem, which hurts performance or fills disks. That's why I was saying /tmp/.dmd-test-run/ should have permissions 0700. I think a better naming scheme would be /tmp/dmd-testrun-username/, or if that already exists with wrong permissions /tmp/dmd-testrun-username-RANDOMCHARS/. The files inside that directory don't need to have random names (afaik). It seems like more practical issue is simply that no regular destruction of /tmp/ happens on your system. I'm not sure what you were implying by this. Deleting anything in /tmp while it's mounted is a very bad idea. The permission-check of /tmp/dmd-testrun-username/ relies on the fact that the directory won't be deleted. If it will, then this introduces a race condition.
Re: Anyone has time for a unittesting issue?
On Saturday, 1 October 2016 at 16:46:56 UTC, Guillaume Boucher wrote: On Saturday, 1 October 2016 at 16:43:29 UTC, Stefan Koch wrote: On Saturday, 1 October 2016 at 16:05:25 UTC, Andrei Alexandrescu wrote: https://issues.dlang.org/show_bug.cgi?id=16568 TIA! -- Andrei Please post some code/instructions to reproduce the issue. The fix for this will be quite simple create a directory with the DDMMYY timestamp as directory name, and bundle the files under it. Any predictable name is a security issue. Use e.g. mkdtemp. Well I guess checking for 700 is sufficient. But this does not scale with multiple users.
Re: Anyone has time for a unittesting issue?
On Saturday, 1 October 2016 at 16:43:29 UTC, Stefan Koch wrote: On Saturday, 1 October 2016 at 16:05:25 UTC, Andrei Alexandrescu wrote: https://issues.dlang.org/show_bug.cgi?id=16568 TIA! -- Andrei Please post some code/instructions to reproduce the issue. The fix for this will be quite simple create a directory with the DDMMYY timestamp as directory name, and bundle the files under it. Any predictable name is a security issue. Use e.g. mkdtemp.
Re: Overloading relational operators separately; thoughts?
On Wednesday, 28 September 2016 at 14:27:58 UTC, Chris Wright wrote: Increment, decrement, and test for equality is sufficient mathematically, but we want programs that terminate in our lifetimes. Only for BigInts you need those three. For ints decrement is not needed. And for most other data types increment/decrement is not sufficient, e.g. for reals or any kind of vectors/matrices.
Re: ADL
On Monday, 5 September 2016 at 23:50:33 UTC, Timon Gehr wrote: One hacky way is to provide a mixin template to create a wrapper type within each module that needs it, with std.typecons.Proxy. Proxy picks up UFCS functions in addition to member functions and turns them into member functions. But this leads to a lot of template bloat, because callers that share the same added UFCS functions don't actually share the instantiation. Also, it only works one level deep and automatically generated Wrapper types are generally prone to be somewhat brittle. I don't think cloning a type just to add functionality can possibly be the right way. A C++-style of customizing behavior is using traits. Those traits would be a compile time argument to the algorithm function. Instead of arg.addone() one would use trait.addone(arg). It is not hard to write a proxy that merges trait and arg into one entity, but this should to be done from the callee. The default trait would be type.addone_trait if it exists, or else some default trait that uses all available functions and member function from the module of the type. In most of the cases this is enough, but it enables adding traits to existing types and also different implementations of the same traits. This gets really bloaty in C++, and that's why usually ADL is preferred, but D has the capability to reduce the overhead to a minimum. It doesn't quite make it possible to separate the implementation of types, algorithms and traits (UFCS) into different modules such that they don't know each other. Either the user has to specify the trait each call or either the type's module or the algorithm's module has to import the traits. What I call traits is very similar to type classes in other languages where (among other features) the traits are automatically being attached to the type. (Type classes are also what C++ concepts originally wanted to be.)
Re: integral to floating point conversion
On Sunday, 3 July 2016 at 09:08:14 UTC, Ola Fosheim Grøstad wrote: On Saturday, 2 July 2016 at 20:17:59 UTC, Andrei Alexandrescu wrote: So what's the fastest way to figure that an integral is convertible to a floating point value precisely (i.e. no other integral converts to the same floating point value)? Thanks! -- Andrei If it is within what the mantissa can represent then it is easy. But you also have to consider the cases where the mantissa is shifted. So the real answer is: n is an unsigned 64 bit integer mbits = representation bits for mantissa +1 tz = trailing_zero_bits(n) lz = leading_zero_bits(n) assert(mbits >= (64 - tz - lz)) This is the correct answer for another definition of "precisely convertible", not the one Andrei gave.
Re: Has someone encountered similar issues with -cov?
On Saturday, 2 July 2016 at 15:15:39 UTC, Guillaume Boucher wrote: E.g. opCast!(int, ubyte) should not require any checks. Or opCast!(long, int) and opCast!(int, int).
Re: Has someone encountered similar issues with -cov?
On Saturday, 2 July 2016 at 12:26:34 UTC, Andrei Alexandrescu wrote: How would you reshape this? It's important that the call to hook is physically at the end of the function and issued just in that place, and that the code does not do any redundant work. Your function does redundant work. E.g. opCast!(int, ubyte) should not require any checks. I also don't understand why opCast!(int, ubyte) is not allowed. The following code should do the same as yours, but without unnecessary checks: U opCast(U, T)(T payload) { import std.traits; enum Tsizeof = is(T==bool) ? 0 : T.sizeof; enum Usizeof = is(U==bool) ? 0 : U.sizeof; enum noCheck = isUnsigned!T == isUnsigned!U && Tsizeof <= Usizeof || isUnsigned!T && Tsizeof < Usizeof; enum checkPayload = !isUnsigned!T && isUnsigned!U; enum checkResult = isUnsigned!T && !isUnsigned!U; static if (checkResult) { static assert(U.sizeof <= T.sizeof); // I don't understand this } if (!checkPayload || payload >= 0) { auto result = cast(U) payload; if (noCheck || result == payload && (!checkResult || result >= 0)) return result; } return hook!U(payload); }
Re: Should % ever "overflow"?
On Friday, 24 June 2016 at 20:43:38 UTC, deadalnix wrote: Most reasonable is numerator = quotient * divisor + remainder Which means it can be negative. Depends on the definition. If division truncates towards negative infinity, the remainder will always be nonegative (in case of a positive divisor). I personally find rounding towards negative infinity the most practical; every time I used modulo, I wanted the result to be in the range [0, divisor). Python does it this way and I find it very convenient.
Re: size_t vs uintptr_t
I was referring to this diff in the pull linked request: -private size_t _alignUp(size_t alignment)(size_t n) +private uintptr_t _alignUp(uintptr_t alignment)(uintptr_t n) size_t is the correct type. There is no reason to change it.
Re: size_t vs uintptr_t
On Tuesday, 14 June 2016 at 21:59:32 UTC, Walter Bright wrote: A related issue is I see much code of the form: cast(size_t)ptr & 3 to check alignment. A better (possibly faster) method is: cast(uint)ptr & 3 because even 64 bit CPUs often operate faster with 32 bit operations (thanks to some research by Andrei). Isn't it guaranteed that x.sizeof >= x.alignof? (At least it is in C and C++.) So the alignment should be of type size_t and not of type uintptr_t. Also in general cast(uint)ptr%alignment is wrong since alignment does not need to be 32 bit. However, cast(size_t)ptr%alignment is be correct in any case.
Re: The Problem With DIPs
On Sunday, 12 June 2016 at 12:16:11 UTC, Dicebot wrote: On 06/09/2016 01:12 AM, Walter Bright wrote: On 6/8/2016 1:47 PM, Dicebot wrote: I will finish description for proposed process this weekend and send it to dmd-internal mail list. Cool! http://forum.dlang.org/thread/d5996d6d-1f8e-2fa7-31a7-177c121a9...@dicebot.lv What are the reasons for putting the DIPs into several directories (Drafts, Approved, Implemented and Discarded)? Rust also did that at first, but they merged them later into one folder (see https://github.com/rust-lang/rfcs/issues/360). If you keep the structure as is, what is the preferred way to link to a certain DIP?
Re: Need a Faster Compressor
On Tuesday, 24 May 2016 at 20:16:32 UTC, Walter Bright wrote: On 5/24/2016 9:22 AM, Timon Gehr wrote: Yes, it does. The compiler does not use exponential space to store the AST. BTW, all types in dmd have a 'deco' string which is the AST linearized as a string. This string is also used to build the mangled names. All the deco's are put into a hashtable, and then all types can be uniquely identified by their address in the hashtable. This reduces type comparisons to a single pointer comparison. There's no reason not to use the compression in the deco name. Just make sure the references are relative and you're set. No exponential space to store the AST. Please, if you change the ABI, do it right the first time. Some arbitrary compression algorithm doesn't solve the problem.
Re: Need a Faster Compressor
On Monday, 23 May 2016 at 20:34:19 UTC, Walter Bright wrote: On 5/23/2016 12:32 PM, Timon Gehr wrote: Isn't it enough to create references to previously embedded mangled symbols (i-th symbol already mangled) while generating the mangled string? That's been covered upthread, and VC++/g++ do that. But as shown, it is inadequate. There's a lot more redundancy than just the identifiers. Yes, not all redundancy is covered. However, I think all non-pathologic blow-ups are avoided. Let's look at the properties of the Itanium C++ ABI mangling: 1. Guaranteed linear size name for recursive types that have exponential size names. 2. Compression speed can be linear to the size of the compressed name (i.e. no need to create an exponential garbage name just to compress it). 3. Decompression easy, possible without tools and speed linear to size of the compressed name. 4. Name retains some redundancy (in itself and when compared to other mangled names), well suited for a follow-up compression. Compare this to apply some arbitrary compression algorithm to a name of exponential size: 1. Exponential size names remain exponential size. Yes, up until the view size, some compression algorithms guarantee that, but they can not guarantee it in the general case. 2. Compression needs the whole name first. 3. Decompression only possible with tools. 4. Multiple mangled names can not be compressed well.
Re: Need a Faster Compressor
On Saturday, 21 May 2016 at 22:07:27 UTC, Walter Bright wrote: As mentioned elsewhere, the C++ mangling scheme has a primitive and ineffective LZ77 scheme built in, so I wouldn't waste time on that. Sorry if I didn't memorize everything in this forum from the last 20 years, can you give a link to some reasoning? The only thing I found are some statements in https://github.com/dlang/dmd/pull/5793: Note that the VC++ and g++ name mangling schemes for C++ each use a similar, but primitive (and fairly ineffective) form of compression. It's like people who invent their own crypto algorithms. The name mangling in the Itanium C++ ABI is similar to LZ77 but heavily optimized for the typical use case in symbol names. I don't really see how the general LZ77 would be better. It's almost as if using information about the actual data leads to a better compression scheme. This is what C++ does, and results are pretty poor compression. Scanning to determine the backward references would consume the same order of time, anyway. It uses a constant amount of time if implemented correctly, which is much faster.
Re: DMD producing huge binaries
On Saturday, 21 May 2016 at 18:25:46 UTC, Walter Bright wrote: On 5/20/2016 11:18 PM, poliklosio wrote: foo!(boo!(bar!(baz!(int))), #1, #2) Where #1 and #2 are special symbols that refer to stuff that was **already in the name**, particularly: #1: bar!(baz!(int)) #2: baz!(int) This is what LZW compression does, except that LZW does it in general rather than just for identifiers. It's more like LZ77 than LZW.