Re: AA invalidating pointers and references..?
bearophile wrote: simendsjo: I haven't worked much with AA's, but I find the key in aa returns a reference to the value to be handy. I think it's better than the following: int value; if( 1 in a ) value = a[1]; or a[1] in a try/catch or other implementations. Your examples have shown me that probably the current design can't be made safe, and you can't use in SafeD code. But performing x in AA is a very useful operation that I want to perform in SafeD code. And in my opinion this code: int value; auto ptr = 1 in a; if (ptr) value = *ptr; Doesn't look better than: int value; if (1 in a) value = a[1]; 2) I don't know what you mean. Does a single lookup often involve several under the hood? If your compiler is naive then code like this: if (1 in a) value = a[1]; requires to perform two searches inside the hash, the first to tell if the key is present, and the second to find it again and fetch its value. A bit better compiler (LDC is already able to do this) can recognize that you are performing two nearby key searches with the same key, and it can remove the second one, essentially replacing that code with this one: int value; auto ptr = 1 in a; if (ptr) value = *ptr; Bye, bearophile You can always use: auto value = 1 in a; if (value) // needs != null? Haven't looked at this in the spec yet. //work with *value But if the compiler can optimize the calls either way, and this is unsafe, a safer way sounds nice.
Re: Problem with std.array(std.regex.splitter())
On 08/09/2010 12:50 AM, bearophile wrote: This D2 code: import std.regex: splitter, regex; import std.array: array; void main() { array(splitter(, abc, de, regex(, *))); } Gives the errors: test.d(4): Error: template std.array.array(Range) if (isForwardRange!(Range)) does not match any function template declaration test.d(4): Error: template std.array.array(Range) if (isForwardRange!(Range)) cannot deduce template function from argument types !()(Splitter!(string)) Do you know what's wrong in it? Bye and thank you, bearophile std.array.array() erroneously requires a forward range, where it should require an input range. Splitter also does not define save(), so it's not a forward range.
Re: d equivilent of java's public static class fields
On 2010-08-08 21:12, %u wrote: I'm porting some code from Java to D and am getting stuck on what Java calls static class fields. I can't find out how to write the functional (or best practices) equivalent in D. (There are other syntax errors in D code, I'm fixing them one by one) # Begin D code (ported from Java code below, and I probably should use an Enum, but haven't) public class Answer { /* I've tried various combinations of syntax here */ static int CORRECT = 0; public const int WRONG = 1; private int _answerCode; private string _answerText; /* */ public this(int answerCode, string answerText) { _answerCode = answerCode; _answerText = answerText; } /* */ public int getAnswerCode() { return _answerCode; } /* */ public string getAnswerText() { return _answerText; } } ### End D code code ### Begin Java code (included to show how it was done in java) public class Answer { public static final int CORRECT = 0; public static final int WRONG = 1; private int _answerCode; private String _answerText; /* */ public Answer(int answerCode, String answerText) { _answerCode = answerCode; _answerText = answerText; } /* */ public int getAnswerCode() { return _answerCode; } /* */ public String getAnswerText() { return _answerText; } } ## End Java code # Begin D code snippet trying to use the Answer class int asd = Answer.CORRECT;-- compile error here try { answer = problem.getAnswer(reply); // grade answer if (answer.getAnswerCode() == Answer.CORRECT)-- compile error here inOut.displayAnswer(Correct); else inOut.displayAnswer(Nope, ~ answer.getAnswerText()); } catch (Exception iae) { inOut.displayAnswer(iae.getMessage()); repeatQuestion = true; // show same question again } # End D code snippet I don't know how you are trying to use your class but I don't see any errors in your code. -- /Jacob Carlborg
Re: d equivilent of java's public static class fields
On 2010-08-08 21:28, Simen kjaeraas wrote: %u throwa...@limewall.org wrote: I'm porting some code from Java to D and am getting stuck on what Java calls static class fields. I can't find out how to write the functional (or best practices) equivalent in D. [snip] static int CORRECT = 0; [snip] int asd = Answer.CORRECT; -- compile error here [snip] if (answer.getAnswerCode() == Answer.CORRECT) -- compile error here The default access level in D is private, so CORRECT will not be available outside the module in which Answer is defined. Since when is the default access level in D private? As you mention, you should probably use an enum for wrong/correct. However, due to lookup rules, an embedded enum would require users to specify Answer.Correctness.CORRECT/WRONG, so separate enums for each might be a better idea. The most common way to expose the stored values in D code would probably be as properties: class Answer { alias int Correctness; enum Correctness CORRECT = 0; enum Correctness WRONG = 1; Correctness _answerCode; string _answerText; @property Correctness answerCode( ) const { return _answerCode; } @property string answerText( ) const { return _answerText; } } -- /Jacob Carlborg
Re: Problem with std.array(std.regex.splitter())
On Monday 09 August 2010 01:13:30 Pelle wrote: std.array.array() erroneously requires a forward range, where it should require an input range. Splitter also does not define save(), so it's not a forward range. Well, the requirement for save() being part of a forward range is fairly recent, and a bunch of ranges which are supposed to be forward ranges don't have them even though they're supposed to. The change was made fairly close to the release of 2.047, I believe, and it was missed for many ranges. It's mostly if not entirely fixed in svn. Actually, if I try and compile Bearophile's code on my machine (which has a fairly recent version of phobos), it compiles just fine. So, I don't know if array() should require an input range or a forward range, but the issue here has to do with recent changes to forward ranges which didn't make it into all forward ranges. It should be fixed with 2.048. - Jonathan M Davis
Re: inheriting ctors?
Philippe Sigaud wrote: On Fri, Aug 6, 2010 at 21:59, Rory Mcguire rjmcgu...@gm_no_ail.com wrote: Here is a possible solution to your problem: -Rory I believe you can get the type of A. Isn't it typeof(super) or std.traits.BaseClassesTuple!B[0] ? B in the latter case being typeof(this) That way, there is no need for the user to provide A, it's automatically found by the template. Warning: I did not test this. And, we know the constructs are of type 'A function(someTypes)' [*], so the 'A function' part is redundant. Hence, the user only needs to provide for the args types and that makes for a cleaner call. * either as a list : mixin(InheritConstructors!(int, double, string)); // I want to inherit the constructors taking one type, build me the __ctors for int, double and string * or, in the case of multi-parameters constructors, wrap them in a tuple: mixin(InheritConstructors!(int, double, Tuple!(int, double)); // I want super(int), super(double) and super(int, double) That means iterating on the type list, and determining if the current type is a tuple or not * if its a 'normal' type, create the corresponding contructor * if it's a Tuple, crack it open and get the types, using the .Types alias std.typecons.Tuples have. Creating a constructor from this typetuple is no different from creating it for one type. To determine if something is a std.typecons.Tuple, you cannot use an is() expression: they do not allow multiple types: enum bool isTuple = is(T == Tuple!U, U...); // no. U... is not allowed. Hmm, enhancement request? So, you can either rely on it having a .Types 'member': template isTuple(T) { enum bool isTuple = is(T.Types); } Pb: that will flag as tuples any type that exposes a .Types alias. Or use a function accepting a Tuple: template isTuple(T) { enum bool isTuple = is(typeof({ void foo(U...)(Tuple!U t) {}; // this function accepts only tuples foo(T.init); // test it }())); } It's ugly as a rat's ass, but it's more solid than the former template. Philippe [*] btw, shouldn't that be A delegate(someTypes)??? I'll see what I can do to shorten it but I'm not sure how to iterate over the Selectors inside the foreach and still be able to skip unselected constructors. Hmmm I suppose I could use a temporary boolean or something. I don't use A delegate(someTuypes) because the compiler says that the type of the constructors is for instance: A function(int x)
Re: inheriting ctors?
I had been trying to use AutoImplement to make something before but it gave me weird errors. I'm going to try using it for implementing this when I get some time. Andrej Mitrovic wrote: Here's an example: [snip]
Re: Problem with std.array(std.regex.splitter())
Jonathan M Davis: Well, the requirement for save() being part of a forward range is fairly recent, and a bunch of ranges which are supposed to be forward ranges don't have them even though they're supposed to. The change was made fairly close to the release of 2.047, I believe, and it was missed for many ranges. It's mostly if not entirely fixed in svn. Actually, if I try and compile Bearophile's code on my machine (which has a fairly recent version of phobos), it compiles just fine. I have tried the latest beta and indeed it works, thank you. Where can I find information about the purposes and meaning of save()? TDPL? Bye, bearophile
Re: Casting away const
On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? -Steve
Re: Problem with std.array(std.regex.splitter())
On Mon, 09 Aug 2010 07:31:21 -0400, bearophile wrote: Jonathan M Davis: Well, the requirement for save() being part of a forward range is fairly recent, and a bunch of ranges which are supposed to be forward ranges don't have them even though they're supposed to. The change was made fairly close to the release of 2.047, I believe, and it was missed for many ranges. It's mostly if not entirely fixed in svn. Actually, if I try and compile Bearophile's code on my machine (which has a fairly recent version of phobos), it compiles just fine. I have tried the latest beta and indeed it works, thank you. Where can I find information about the purposes and meaning of save()? TDPL? It should be in the documentation of std.range.isForwardRange(), but Andrei seems to have forgotten it. He did describe it in his 'On Iteration' article, though: http://www.informit.com/articles/article.aspx?p=1407357 Check out page 7, section 'Forward Ranges'. (I think the whole article is worth reading, if you haven't already -- it really helped me understand ranges.) -Lars
Re: Casting away const
Steven Schveighoffer: I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? In my opinion if this thing is well designed then you go in undefined behaviour only when you change the contents of something after you have removed its const nature with a cast. Just casting const away and then reading the data can't be undefined behaviour, otherwise casting const away is useless and can be totally disallowed. Bye, bearophile
Re: Casting away const
Steven Schveighoffer wrote: On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? -Steve I think you're wrong. It's OK to cast away const, as long as you don't modify the thing which is supposed to be const. But if you modify it, there's no way the compiler can guarantee that your code will work. Anything could happen.
Re: Casting away const
On Mon, 09 Aug 2010 09:57:47 -0400, bearophile bearophileh...@lycos.com wrote: Steven Schveighoffer: I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? In my opinion if this thing is well designed then you go in undefined behaviour only when you change the contents of something after you have removed its const nature with a cast. Just casting const away and then reading the data can't be undefined behaviour, otherwise casting const away is useless and can be totally disallowed. Casting away const just to read the data is useless. You can read const data without a cast. But my understanding is that casting away const to write should be doable if you know what you're doing. If this is undefined behavior, then that's fine, I'm just unclear on what undefined behavior actually means. I thought undefined behavior means that you cannot count on the behavior to work in the future. An example of where casting away const to write should be allowed is for a hypothetical mutable member: class C { private Mutable!(int) cache = -1; int expensiveFunction() const { return cache == -1 ? cache = _expensiveFunctionImpl() : cache; } private int _expensiveFunctionImpl() const {...} } If this is undefined, then something like this cannot be relied on, even when performance is critical. -Steve
Re: Casting away const
On Mon, 09 Aug 2010 10:11:39 -0400, Don nos...@nospam.com wrote: Steven Schveighoffer wrote: On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? -Steve I think you're wrong. It's OK to cast away const, as long as you don't modify the thing which is supposed to be const. But if you modify it, there's no way the compiler can guarantee that your code will work. Anything could happen. But then what is the point of casting away const? If you are not going to modify it, then there is no reason to cast it away. What about how Rebindable works? It doesn't exactly cast away const, it uses a union, but the effect is the same. Is this OK simply because a union is used? Also, see my reply to bearophile, with hypothetical example. -Steve
Re: Casting away const
Steven Schveighoffer wrote: On Mon, 09 Aug 2010 09:57:47 -0400, bearophile bearophileh...@lycos.com wrote: Steven Schveighoffer: I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? In my opinion if this thing is well designed then you go in undefined behaviour only when you change the contents of something after you have removed its const nature with a cast. Just casting const away and then reading the data can't be undefined behaviour, otherwise casting const away is useless and can be totally disallowed. Casting away const just to read the data is useless. You can read const data without a cast. No you can't. You can't pass it to a C function. But my understanding is that casting away const to write should be doable if you know what you're doing. If this is undefined behavior, then that's fine, I'm just unclear on what undefined behavior actually means. I thought undefined behavior means that you cannot count on the behavior to work in the future. An example of where casting away const to write should be allowed is for a hypothetical mutable member: class C { private Mutable!(int) cache = -1; int expensiveFunction() const { return cache == -1 ? cache = _expensiveFunctionImpl() : cache; } private int _expensiveFunctionImpl() const {...} } If this is undefined, then something like this cannot be relied on, even when performance is critical. -Steve I really can't see how the compiler could make that work, without destroying most of the benefits of const. For example, if that code is legal, it disallows most const-related optimisation.
Re: Casting away const
Hello Steven, On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? I think you are right re the meaning of those terms but I think what you thought it to be is more along the lines of what is correct. I /think/ the situation is that there are things that will work reliably and things that result in undefined behavior and you're on your own figuring out what is what. -Steve -- ... IXOYE
[OT] Is this more readable, or just way too verbose?
I took splitlines from std.string, which is a simple, short method. S[] splitlines(S)(S s) { size_t istart; auto result = Appender!(S[])(); foreach (i; 0 .. s.length) { immutable c = s[i]; if (c == '\r' || c == '\n') { result.put(s[istart .. i]); istart = i + 1; if (c == '\r' i + 1 s.length s[i + 1] == '\n') { i++; istart++; } } } if (istart != s.length) { result.put(s[istart .. $]); } return result.data; } I guess it takes less than 30 seconds to fully understand this method. Then I rap.. I mean refactored it to this: S[] mysplitlines(S)(S s) { const CR = '\r'; const LF = '\n'; size_t istart; auto result = Appender!(S[])(); foreach (i; 0 .. s.length) { immutable c = s[i]; immutable isCR = (c == CR); immutable isLF = (c == LF); if (isCR || isLF) { auto line = s[istart .. i]; result.put(line); istart = i + 1; // Might be CRLF. In that case we need to consume LF too if (isCR) { immutable hasMoreCharacters = (i + 1 s.length); immutable nextIsLF = hasMoreCharacters (s[i + 1] == LF); immutable isCRLF = isCR nextIsLF; if (isCRLF) { i++; istart++; } } } } immutable lineNotEmpty = (istart != s.length); if (lineNotEmpty) { auto lastLine = s[istart .. $]; result.put(lastLine); } return result.data; } Yes, I'm reading some books now and don't have much experience :) It went from a small 26 line, very readable function to 48 lines (85% increase!) with many more temporary variables.. So... Do you think this kind of code is (more) readable, or just way too verbose and doing more harm than good? And will the compiler generate slower code, or should the optimizer be able to inline the temporaries?
Re: Casting away const
Hello Steven, On Mon, 09 Aug 2010 10:11:39 -0400, Don nos...@nospam.com wrote: Steven Schveighoffer wrote: On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? -Steve I think you're wrong. It's OK to cast away const, as long as you don't modify the thing which is supposed to be const. But if you modify it, there's no way the compiler can guarantee that your code will work. Anything could happen. But then what is the point of casting away const? If you are not going to modify it, then there is no reason to cast it away. There are some cases where non-const pointers are used but never modified (C api's for instance) cast as always is just a way subvert the type system where it gets in your way. -- ... IXOYE
Re: Casting away const
On Mon, 09 Aug 2010 10:27:09 -0400, Don nos...@nospam.com wrote: Steven Schveighoffer wrote: On Mon, 09 Aug 2010 09:57:47 -0400, bearophile bearophileh...@lycos.com wrote: Steven Schveighoffer: I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? In my opinion if this thing is well designed then you go in undefined behaviour only when you change the contents of something after you have removed its const nature with a cast. Just casting const away and then reading the data can't be undefined behaviour, otherwise casting const away is useless and can be totally disallowed. Casting away const just to read the data is useless. You can read const data without a cast. No you can't. You can't pass it to a C function. Sure you can. extern(C) int strlen(const(char) *arg); But my understanding is that casting away const to write should be doable if you know what you're doing. If this is undefined behavior, then that's fine, I'm just unclear on what undefined behavior actually means. I thought undefined behavior means that you cannot count on the behavior to work in the future. An example of where casting away const to write should be allowed is for a hypothetical mutable member: class C { private Mutable!(int) cache = -1; int expensiveFunction() const { return cache == -1 ? cache = _expensiveFunctionImpl() : cache; } private int _expensiveFunctionImpl() const {...} } If this is undefined, then something like this cannot be relied on, even when performance is critical. -Steve I really can't see how the compiler could make that work, without destroying most of the benefits of const. For example, if that code is legal, it disallows most const-related optimisation. Why not? What possible optimization can the compiler do here? Mutable has an assign operation that is labeled as const, it should be callable by the compiler. I haven't really seen what const optimizations can be, so maybe an example (even if unimplemented) is helpful. -Steve
Re: Casting away const
On Mon, 09 Aug 2010 10:37:14 -0400, BCS n...@anon.com wrote: Hello Steven, On Mon, 09 Aug 2010 10:11:39 -0400, Don nos...@nospam.com wrote: Steven Schveighoffer wrote: On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? -Steve I think you're wrong. It's OK to cast away const, as long as you don't modify the thing which is supposed to be const. But if you modify it, there's no way the compiler can guarantee that your code will work. Anything could happen. But then what is the point of casting away const? If you are not going to modify it, then there is no reason to cast it away. There are some cases where non-const pointers are used but never modified (C api's for instance) cast as always is just a way subvert the type system where it gets in your way. C's api can be modified at declaration. It has no mangling, so you can type it how it should be (if C had const). For example: extern(C) int strlen(const(char)* str); I find that much more pleasant than having to cast away const. -Steve
Re: Casting away const
On Mon, 09 Aug 2010 10:24:56 -0400, BCS n...@anon.com wrote: Hello Steven, On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? I think you are right re the meaning of those terms but I think what you thought it to be is more along the lines of what is correct. I /think/ the situation is that there are things that will work reliably and things that result in undefined behavior and you're on your own figuring out what is what. I'm sort of interpreting what you're saying is: In some cases, you can cast away const and modify the variable with no adverse effects, but we can't tell you which cases those are. Which is kind of like saying yes, casting away const is allowed, but only people who wrote the compiler can do it. -Steve
Re: Casting away const
Hello Steven, On Mon, 09 Aug 2010 09:57:47 -0400, bearophile bearophileh...@lycos.com wrote: Steven Schveighoffer: I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? In my opinion if this thing is well designed then you go in undefined behaviour only when you change the contents of something after you have removed its const nature with a cast. Just casting const away and then reading the data can't be undefined behaviour, otherwise casting const away is useless and can be totally disallowed. Casting away const just to read the data is useless. You can read const data without a cast. But my understanding is that casting away const to write should be doable if you know what you're doing. If this is undefined behavior, then that's fine, I'm just unclear on what undefined behavior actually means. I thought undefined behavior means that you cannot count on the behavior to work in the future. Undefined behavior implies exactly that, once you enter the realm of undefined behavior, /anything/ that happens is your fault, the program can do anything at all and sill be considered a conforming program. It need not even behave the same between one run and the next. The practical implications of this are that compilers are allowed to always assume the code never does anything that results in undefined behavior and generate code that is wrong in any number of ways if that assumption fails. -- ... IXOYE
Re: Casting away const
Hello Steven, On Mon, 09 Aug 2010 10:37:14 -0400, BCS n...@anon.com wrote: Hello Steven, On Mon, 09 Aug 2010 10:11:39 -0400, Don nos...@nospam.com wrote: Steven Schveighoffer wrote: On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? -Steve I think you're wrong. It's OK to cast away const, as long as you don't modify the thing which is supposed to be const. But if you modify it, there's no way the compiler can guarantee that your code will work. Anything could happen. But then what is the point of casting away const? If you are not going to modify it, then there is no reason to cast it away. There are some cases where non-const pointers are used but never modified (C api's for instance) cast as always is just a way subvert the type system where it gets in your way. C's api can be modified at declaration. It has no mangling, so you can type it how it should be (if C had const). For example: extern(C) int strlen(const(char)* str); I find that much more pleasant than having to cast away const. OTOH that is effectively a hidden cast and has 100% of the same issues (re undefined behavior) as casting away const while being slightly harder to find. -- ... IXOYE
Re: Casting away const
Hello Steven, On Mon, 09 Aug 2010 10:24:56 -0400, BCS n...@anon.com wrote: Hello Steven, On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? I think you are right re the meaning of those terms but I think what you thought it to be is more along the lines of what is correct. I /think/ the situation is that there are things that will work reliably and things that result in undefined behavior and you're on your own figuring out what is what. I'm sort of interpreting what you're saying is: In some cases, you can cast away const and modify the variable with no adverse effects, but we can't tell you which cases those are. Yes and no. Yes, sometimes casting away const and then writing to the pointer doesn't crash your program (or do anything else) but no that's not what I was saying. It's still undefined behavior even if it works. What your on your own with is making sure you don't write to the pointer. Once you cast, the compiler won't check your work. Which is kind of like saying yes, casting away const is allowed, but only people who wrote the compiler can do it. -Steve -- ... IXOYE
Re: Casting away const
On Mon, 09 Aug 2010 10:53:48 -0400, BCS n...@anon.com wrote: Hello Steven, On Mon, 09 Aug 2010 10:37:14 -0400, BCS n...@anon.com wrote: Hello Steven, On Mon, 09 Aug 2010 10:11:39 -0400, Don nos...@nospam.com wrote: Steven Schveighoffer wrote: On Sun, 08 Aug 2010 17:56:25 -0400, simendsjo simen.end...@pandavre.com wrote: I'm totally new to the const/immutable thing, so this might be a naive question.. The spec says: modification after casting away const = undefined behavior I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? -Steve I think you're wrong. It's OK to cast away const, as long as you don't modify the thing which is supposed to be const. But if you modify it, there's no way the compiler can guarantee that your code will work. Anything could happen. But then what is the point of casting away const? If you are not going to modify it, then there is no reason to cast it away. There are some cases where non-const pointers are used but never modified (C api's for instance) cast as always is just a way subvert the type system where it gets in your way. C's api can be modified at declaration. It has no mangling, so you can type it how it should be (if C had const). For example: extern(C) int strlen(const(char)* str); I find that much more pleasant than having to cast away const. OTOH that is effectively a hidden cast and has 100% of the same issues (re undefined behavior) as casting away const while being slightly harder to find. But you just said that casting and reading is not undefined? Isn't this the same thing? Const is such a strange beast because it plays no role in code generation, it's effectively only a tool to help the compiler decide what is possible. It doesn't occupy any space or translate whatsoever to the underlying code. I think there are definite good uses for writing to const or immutable data besides ones that can be stored in ROM. That is, if you are sure a const or immutable piece of data is on the heap/stack, it should be reasonable to be able to modify it for performance gains. -Steve
std.regex.match
A question about std.regex.match() design. I am not sure, so I ask here first (if the ideas are sane I will write an enhancement request later). This is the current syntax you have to use to iterated on the matches: foreach (m; match(text, regex(r\d)).captures) {} The regex() there is useful because you can add attributes like g as second argument, but often I don't need attributes. So is it possible to make match() accept a syntax like this too, that is more handy (the second argument of match() can be just a string, and there is no .captures): foreach (m; match(text, r\d)) {} Bye, bearophile
Re: Casting away const
On Mon, 09 Aug 2010 11:04:40 -0400, Steven Schveighoffer schvei...@yahoo.com wrote: On Mon, 09 Aug 2010 10:53:48 -0400, BCS n...@anon.com wrote: OTOH that is effectively a hidden cast and has 100% of the same issues (re undefined behavior) as casting away const while being slightly harder to find. But you just said that casting and reading is not undefined? Isn't this the same thing? Const is such a strange beast because it plays no role in code generation, it's effectively only a tool to help the compiler decide what is possible. It doesn't occupy any space or translate whatsoever to the underlying code. I think there are definite good uses for writing to const or immutable data besides ones that can be stored in ROM. That is, if you are sure a const or immutable piece of data is on the heap/stack, it should be reasonable to be able to modify it for performance gains. I should say, when performance gains are not possible because of the limitations of the const/immutable notation. The classic example is the mutable cache for avoiding recalculations on an immutable object. -Steve
Re: Casting away const
Steven Schveighoffer: extern(C) int strlen(const(char)* str); C has no const(char)* so I am now thinking about a possible D2 diagnostic enhancement request that turns that line of code into a compile time error :-) Bye, bearophile
Re: Casting away const
On Mon, 09 Aug 2010 11:15:38 -0400, bearophile bearophileh...@lycos.com wrote: Steven Schveighoffer: extern(C) int strlen(const(char)* str); C has no const(char)* so I am now thinking about a possible D2 diagnostic enhancement request that turns that line of code into a compile time error :-) But an extern(C) function does not have to be written in C :) -Steve
Re: What on earth is a ref function?
simendsjo simen.end...@pandavre.com wrote: The spec is very short here, and the example doesn't give me much.. // I thought allows functinos to return by reference meant it could return local variables.. ref int* ptr() { auto p = new int; *p = 12; return p; // Error: escaping local variable } This fails because p itself is stack allocated. By reference means it returns a hidden pointer to something. Because this is a pointer, you can get the address of the returned value, and do things to it. // So whats the difference between these functions? ref int val() { auto p = new int; assert(*p == 0); *p = 10; assert(*p == 10); return *p; } This returns what is in effect p - a pointer (reference) to an int. int val2() { auto p = new int; *p = 10; return *p; } This returns simply the value of *p. unittest { assert(val() == 10); assert(val2() == 10); auto retvalue = val() = 99; // References can be lvalues.. What? assert(retvalue == 99); } Giving an example of what one can do with a reference: ref int foo( ref int val ) { return ++value; } int n = 3; foo( n ) = 4; assert( n == 4 ); assert( foo( n ) == 5 ); -- Simen
Re: Casting away const
Steven Schveighoffer: But an extern(C) function does not have to be written in C :) You are right. But that function written in an arbitrary language has to follow the C interface rules and limitations, and among those there is no way to define a variable to be const(char)*. So in that line of code you are writing something that can't be enforced. Generally D design refuses features that the compiler is unable to verify. So I think an enhancement request to disallow that is good here. An extern(C) call has to specify only things that are understood by the C interface. On the other hand in C you have const, but its semantics is different. Uhm... Bye, bearophile
Re: Casting away const
Hello Steven, On Mon, 09 Aug 2010 10:53:48 -0400, BCS n...@anon.com wrote: C's api can be modified at declaration. It has no mangling, so you can type it how it should be (if C had const). For example: extern(C) int strlen(const(char)* str); I find that much more pleasant than having to cast away const. OTOH that is effectively a hidden cast and has 100% of the same issues (re undefined behavior) as casting away const while being slightly harder to find. But you just said that casting and reading is not undefined? Isn't this the same thing? Casting away const or tacking const into a extern(C) prototype is safe under exactly the same conditions. The gains a savings of a few keystrokes and looses some degree of findability, aside from that, there is effectively no difference between them. if you are sure a const or immutable piece of data is on the heap/stack, it should be reasonable to be able to modify it for performance gains. A conforming compiler can be implemented in such a way that you can never be sure of that without looking at the generated asm or even in such a way that it can't be know till runtime. -- ... IXOYE
Re: Casting away const
Steven Schveighoffer schvei...@yahoo.com wrote: class C { private Mutable!(int) cache = -1; int expensiveFunction() const { return cache == -1 ? cache = _expensiveFunctionImpl() : cache; } private int _expensiveFunctionImpl() const {...} } If this is undefined, then something like this cannot be relied on, even when performance is critical. -Steve I really can't see how the compiler could make that work, without destroying most of the benefits of const. For example, if that code is legal, it disallows most const-related optimisation. Why not? What possible optimization can the compiler do here? Mutable has an assign operation that is labeled as const, it should be callable by the compiler. I haven't really seen what const optimizations can be, so maybe an example (even if unimplemented) is helpful. The compiler may decide to store the value of cache in a register, and use that value instead of fetching it after _expensiveFunctionImpl is called. That's the simplest example I could come up with. -- Simen
Re: d equivilent of java's public static class fields
Jacob Carlborg d...@me.com wrote: Since when is the default access level in D private? Uhm, since I made it up? Sorry about that, I believe I mixed it up with C++. -- Simen
Re: Casting away const
On Mon, 09 Aug 2010 11:31:18 -0400, Simen kjaeraas simen.kja...@gmail.com wrote: Steven Schveighoffer schvei...@yahoo.com wrote: class C { private Mutable!(int) cache = -1; int expensiveFunction() const { return cache == -1 ? cache = _expensiveFunctionImpl() : cache; } private int _expensiveFunctionImpl() const {...} } If this is undefined, then something like this cannot be relied on, even when performance is critical. -Steve I really can't see how the compiler could make that work, without destroying most of the benefits of const. For example, if that code is legal, it disallows most const-related optimisation. Why not? What possible optimization can the compiler do here? Mutable has an assign operation that is labeled as const, it should be callable by the compiler. I haven't really seen what const optimizations can be, so maybe an example (even if unimplemented) is helpful. The compiler may decide to store the value of cache in a register, and use that value instead of fetching it after _expensiveFunctionImpl is called. That's the simplest example I could come up with. The compiler will rewrite the code as follows: return cache.opEquals(-1) ? cache.opAssign(_expensiveFunctionImpl()) : cache.xxx; I'm assuming for cache.xxx that it's some sort of alias this to a getter function. All of these function would be const. We can define the opAssign in such a way that it cannot be inlined, forcing the compiler to assume nothing about the result of opAssign. Note also that the optimization you stated is not possible, even without casting away const, but would be possible on an immutable class. But the fact that the compiler cannot peek into the implementation of the opAssign means it's forced to make no assumptions about the result of opAssign. How does one write a conforming compiler that alters the result of this? -Steve
Re: Casting away const
Am 09.08.2010 17:31, schrieb bearophile: Steven Schveighoffer: But an extern(C) function does not have to be written in C :) You are right. But that function written in an arbitrary language has to follow the C interface rules and limitations, and among those there is no way to define a variable to be const(char)*. So in that line of code you are writing something that can't be enforced. Generally D design refuses features that the compiler is unable to verify. So I think an enhancement request to disallow that is good here. An extern(C) call has to specify only things that are understood by the C interface. On the other hand in C you have const, but its semantics is different. Uhm... Bye, bearophile I think, that isn't a good idea. I mean const-ness a compile time thing so the c abi has no problem with it. What's wrong when I define a extern(c) bool thinkeAboutMyInt(const int* x) { } I want to inform the D typesystem that I'm not going to change the int but I need a pointer because the adress is important. I want this function to be also callable outside D (eg C). Mafi
Re: Casting away const
On Mon, 09 Aug 2010 10:35:02 -0400, Steven Schveighoffer wrote: On Mon, 09 Aug 2010 10:27:09 -0400, Don nos...@nospam.com wrote: Steven Schveighoffer wrote: On Mon, 09 Aug 2010 09:57:47 -0400, bearophile bearophileh...@lycos.com wrote: Steven Schveighoffer: I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? In my opinion if this thing is well designed then you go in undefined behaviour only when you change the contents of something after you have removed its const nature with a cast. Just casting const away and then reading the data can't be undefined behaviour, otherwise casting const away is useless and can be totally disallowed. Casting away const just to read the data is useless. You can read const data without a cast. No you can't. You can't pass it to a C function. Sure you can. extern(C) int strlen(const(char) *arg); But my understanding is that casting away const to write should be doable if you know what you're doing. If this is undefined behavior, then that's fine, I'm just unclear on what undefined behavior actually means. I thought undefined behavior means that you cannot count on the behavior to work in the future. An example of where casting away const to write should be allowed is for a hypothetical mutable member: class C { private Mutable!(int) cache = -1; int expensiveFunction() const { return cache == -1 ? cache = _expensiveFunctionImpl() : cache; } private int _expensiveFunctionImpl() const {...} } If this is undefined, then something like this cannot be relied on, even when performance is critical. -Steve I really can't see how the compiler could make that work, without destroying most of the benefits of const. For example, if that code is legal, it disallows most const-related optimisation. Why not? What possible optimization can the compiler do here? Mutable has an assign operation that is labeled as const, it should be callable by the compiler. I haven't really seen what const optimizations can be, so maybe an example (even if unimplemented) is helpful. The compiler does an optimization on const/immutable struct members which I reported as a bug: http://d.puremagic.com/issues/show_bug.cgi?id=3449 -Lars
std.string.chomp error
The documentation says /*** * Returns s[] sans trailing delimiter[], if any. * If delimiter[] is null, removes trailing CR, LF, or CRLF, if any. */ To adhere to the documentation, chomp must be changed from: C[] chomp(C, C1)(C[] s, in C1[] delimiter) { if (endsWith(s, delimiter)) { return s[0 .. $ - delimiter.length]; } return s; } to: C[] chomp(C, C1)(C[] s, in C1[] delimiter) { if (delimiter == null) return chomp(s); else if (endsWith(s, delimiter)) return s[0 .. $ - delimiter.length]; else return s; }
Re: std.string.chomp error
On Mon, 09 Aug 2010 18:58:36 +0200, simendsjo wrote: The documentation says /*** * Returns s[] sans trailing delimiter[], if any. * If delimiter[] is null, removes trailing CR, LF, or CRLF, if any. */ To adhere to the documentation, chomp must be changed from: C[] chomp(C, C1)(C[] s, in C1[] delimiter) { if (endsWith(s, delimiter)) { return s[0 .. $ - delimiter.length]; } return s; } to: C[] chomp(C, C1)(C[] s, in C1[] delimiter) { if (delimiter == null) return chomp(s); else if (endsWith(s, delimiter)) return s[0 .. $ - delimiter.length]; else return s; } Either that, or the documentation for it needs to be changed. Anyway, it would be great if you'd report this. http://d.puremagic.com/issues/ Thanks! -Lars
Re: std.string.chomp error
Lars T. Kyllingstad: Either that, or the documentation for it needs to be changed. Anyway, it would be great if you'd report this. A really basic unit testing is able to catch an error like this. This means Phobos needs more unit tests. Stuff that may be added to that unittest: import std.stdio, std.string; void main() { assert(chomp(hello) == hello); assert(chomp(hello\n) == hello); assert(chomp(hello\r\n) == hello); assert(chomp(hello, ) == hello); assert(chomp(hello\n, ) == hello); assert(chomp(hello\r\n, ) == hello); assert(chomp(hello\r\n, ) == hello); assert(chomp(helloxxx, x) == helloxx); } But instead of: if (delimiter == null) Is better to write: if (delimiter.length == 0) Or: if (delimiter == ) See http://d.puremagic.com/issues/show_bug.cgi?id=3889 Bye, bearophile
Re: Casting away const
Mafi: I think, that isn't a good idea. I agree, that idea doesn't work well. Bye, bearophile
Re: Casting away const
bearophile wrote: Mafi: I think, that isn't a good idea. I agree, that idea doesn't work well. Bye, bearophile I think it still is a good idea to forbid this in safe mode. Perhaps in trusted too.
Re: Casting away const
On Mon, 09 Aug 2010 14:39:58 -0400, Lutger lutger.blijdest...@gmail.com wrote: bearophile wrote: Mafi: I think, that isn't a good idea. I agree, that idea doesn't work well. Bye, bearophile I think it still is a good idea to forbid this in safe mode. Perhaps in trusted too. Note, this isn't any less safe than defining whatever you want for a C function: extern(C) int strlen(int x); C has no mangling, so there is no storage of parameter types in the symbol. You can call any C function with whatever parameters you want to define for them. Making some set of parameters illegal because in some cases it might not be true where you don't prevent it in others because you can't prove it, is just simply useless. -Steve
Re: Casting away const
Steven Schveighoffer wrote: On Mon, 09 Aug 2010 14:39:58 -0400, Lutger lutger.blijdest...@gmail.com wrote: bearophile wrote: Mafi: I think, that isn't a good idea. I agree, that idea doesn't work well. Bye, bearophile I think it still is a good idea to forbid this in safe mode. Perhaps in trusted too. Note, this isn't any less safe than defining whatever you want for a C function: extern(C) int strlen(int x); C has no mangling, so there is no storage of parameter types in the symbol. You can call any C function with whatever parameters you want to define for them. Making some set of parameters illegal because in some cases it might not be true where you don't prevent it in others because you can't prove it, is just simply useless. -Steve Well you manually add typing, I think that is useful. But come to think of it, extern(C) functions should not be allowed in @safe code at all, only via @trusted and then the typing is useful. Perhaps this has been talked about, but I'm not sure how far @trusted can be allowed to go.
Re: Casting away const
Steven Schveighoffer schvei...@yahoo.com wrote: Note also that the optimization you stated is not possible, even without casting away const, but would be possible on an immutable class. But the fact that the compiler cannot peek into the implementation of the opAssign means it's forced to make no assumptions about the result of opAssign You're right, I was thinking of immutable. -- Simen
Re: Casting away const
Simen kjaeraas simen.kja...@gmail.com wrote: Steven Schveighoffer schvei...@yahoo.com wrote: Note also that the optimization you stated is not possible, even without casting away const, but would be possible on an immutable class. But the fact that the compiler cannot peek into the implementation of the opAssign means it's forced to make no assumptions about the result of opAssign You're right, I was thinking of immutable. This said, one of the reasons casting away const is undefined, is because the underlying type may be immutable. -- Simen
Re: Casting away const
On Mon, 09 Aug 2010 15:49:12 -0400, Simen kjaeraas simen.kja...@gmail.com wrote: Simen kjaeraas simen.kja...@gmail.com wrote: Steven Schveighoffer schvei...@yahoo.com wrote: Note also that the optimization you stated is not possible, even without casting away const, but would be possible on an immutable class. But the fact that the compiler cannot peek into the implementation of the opAssign means it's forced to make no assumptions about the result of opAssign You're right, I was thinking of immutable. This said, one of the reasons casting away const is undefined, is because the underlying type may be immutable. Right. After reading all these replies, I think the way it looks to me is technically it's undefined to cast away const/immutable and write the data. But, in certain circumstances, I think it will be possible to write portable code that works on all compilers that does this. It's like a threading race condition. If you simply allow unchecked access to a variable, it's undefined, you get races and can be using a partially written value, but slap a mutex around it, and the variable suddenly becomes well defined and behaves perfectly. The compiler cannot guarantee this, nor detect it, but the programmer can determine based on analysis of all the code that it's safe. -Steve
Re: Casting away const
On Monday, August 09, 2010 07:13:31 Steven Schveighoffer wrote: Casting away const just to read the data is useless. You can read const data without a cast. That's not actually quite true. If all code were const-correct, then it would be, but much of D is not. For instance, toHash() is not const even though it should be. The result is that if you need to call it with a const object, you have to cast away the constness. No writing is going on there (unless the writer of the toHash() function in the derived class(es) screwed it up), but you can't call it with a const object. I've run into plenty of similar situations in C++ where whoever wrote the code didn't choose to use const at all, and it made making that code deal with const a royal pain if not totally unreasonable. Casting away constness in cases where you knew that no write was going to take place or just dropping the constness in in your code were the only two options. If anything, my reaction would have been that the programmer has no business writing to anything that they cast away the constness of. Dealing with code which _could_ and _should_ be const but isn't is the only place that I've ever even considered casting away const. - Jonathan M Davis
Re: Problem with std.array(std.regex.splitter())
On Monday, August 09, 2010 04:31:21 bearophile wrote: Jonathan M Davis: Well, the requirement for save() being part of a forward range is fairly recent, and a bunch of ranges which are supposed to be forward ranges don't have them even though they're supposed to. The change was made fairly close to the release of 2.047, I believe, and it was missed for many ranges. It's mostly if not entirely fixed in svn. Actually, if I try and compile Bearophile's code on my machine (which has a fairly recent version of phobos), it compiles just fine. I have tried the latest beta and indeed it works, thank you. Where can I find information about the purposes and meaning of save()? TDPL? Bye, bearophile save() gives you a generic way to get a copy of the range so that you can mess with the copy without altering the original. That way you don't have to worry about the different copy semantics for classes, structs, and arrays. - Jonathan M Davis
Re: std.string.chomp error
On 09.08.2010 19:16, Lars T. Kyllingstad wrote: On Mon, 09 Aug 2010 18:58:36 +0200, simendsjo wrote: The documentation says /*** * Returns s[] sans trailing delimiter[], if any. * If delimiter[] is null, removes trailing CR, LF, or CRLF, if any. */ To adhere to the documentation, chomp must be changed from: C[] chomp(C, C1)(C[] s, in C1[] delimiter) { if (endsWith(s, delimiter)) { return s[0 .. $ - delimiter.length]; } return s; } to: C[] chomp(C, C1)(C[] s, in C1[] delimiter) { if (delimiter == null) return chomp(s); else if (endsWith(s, delimiter)) return s[0 .. $ - delimiter.length]; else return s; } Either that, or the documentation for it needs to be changed. Anyway, it would be great if you'd report this. http://d.puremagic.com/issues/ Thanks! -Lars Ok; http://d.puremagic.com/issues/show_bug.cgi?id=4608
Justify text
Phobos assumes that you only want to fill with spaces when justifying text. I merged the functions with a user supplied character. Don't think it should be much slower.. Just the switch extra switch if the function is inlined.. (but don't take my word for it :) )? enum Alignment { Right, Left, Center } string justify(string text, Alignment alignment, int width, char symbol) { if (text.length = width) return text; char[] result = new char[width]; switch(alignment) { case Alignment.Right: result[0 .. width - text.length] = symbol; result[width - text.length .. width] = text; break; case Alignment.Center: int left = (width - text.length) / 2; result[0 .. left] = symbol; result[left .. left + text.length] = text; result[left + text.length .. width] = symbol; break; case Alignment.Left: result[0 .. text.length] = text; result[text.length .. width] = symbol; break; default: assert(false); } return assumeUnique(result); } string ljustify(string s, int width) { return justify(s, Alignment.Left, width, ' '); } string rjustify(string s, int width) { return justify(s, Alignment.Right, width, ' '); } string center(string s, int width) { return justify(s, Alignment.Center, width, ' '); }
Re: Casting away const
On Mon, 09 Aug 2010 17:15:41 -0400, Jonathan M Davis jmdavisp...@gmail.com wrote: On Monday, August 09, 2010 07:13:31 Steven Schveighoffer wrote: Casting away const just to read the data is useless. You can read const data without a cast. That's not actually quite true. If all code were const-correct, then it would be, but much of D is not. For instance, toHash() is not const even though it should be. The result is that if you need to call it with a const object, you have to cast away the constness. No writing is going on there (unless the writer of the toHash() function in the derived class(es) screwed it up), but you can't call it with a const object. Then the author failed to make it const, and it's a bug in the function definition. Casting away const if you don't write is crap, and should be treated as suspiciously as code that writes to const data. What if calculating the hash is expensive, and you know you don't have to recalculate it, you might cache it as a member of the class. Believe me, if a programmer can do it, he will. Documentation saying don't do this! isn't enough. I've run into plenty of similar situations in C++ where whoever wrote the code didn't choose to use const at all, and it made making that code deal with const a royal pain if not totally unreasonable. Casting away const in C++ and writing to the data I think is not undefined. I believe that's one of Walter's gripes with C++ const. -Steve
Re: std.string.chomp error
On 09.08.2010 23:58, bearophile wrote: simendsjo: Ok; http://d.puremagic.com/issues/show_bug.cgi?id=4608 You seem to have missed my answer :-) Bye, bearophile No, but I don't know if it's the documentation or implementation that's correct.
Re: Justify text
On 09.08.2010 23:59, simendsjo wrote: return justify(s, Alignment.Right, width, ' '); Forgot zfill: string zfill(string s, int width) { return justify(s, Alignment.Right, width, '0'); }
Re: DirectX 11 bindings?
No one?
Missing test in std.string.replace
Replacing with / null is missing. I first looked at the function and modified it. Quickly noticed that a few unit tests were missing: assert(replace(foo, foo, ) == ); assert(replace(foo, foo, null) == );
Re: Missing test in std.string.replace
On 10.08.2010 00:29, simendsjo wrote: Replacing with / null is missing. I first looked at the function and modified it. Quickly noticed that a few unit tests were missing: assert(replace(foo, foo, ) == ); assert(replace(foo, foo, null) == ); I refactored replace to understand what was going on (related to my post is this more readable). I've seen a couple of functions using Appender, and it's documentation says it's faster than ~=. I tried to change char[] result to Appender, but dmd crashed... string replace(string s, string from, string to) { if (from.length == 0) // Nothing to replace return s; char[] result; for (size_t searchIndex; searchIndex s.length; ) { auto rest = s[searchIndex .. s.length]; auto fromIndex = indexOf(rest, from); bool nothingToReplace = (fromIndex == -1); if (nothingToReplace) { bool firstSearch = (searchIndex == 0); if (firstSearch) { // Never found, so just return s return s; } result ~= rest; break; } auto beforeFrom = s[searchIndex .. searchIndex + fromIndex]; result ~= beforeFrom; result ~= to; searchIndex += fromIndex + from.length; } return assumeUnique(result); }
Re: std.string.chomp error
On 09.08.2010 19:34, bearophile wrote: Lars T. Kyllingstad: Either that, or the documentation for it needs to be changed. Anyway, it would be great if you'd report this. A really basic unit testing is able to catch an error like this. This means Phobos needs more unit tests. Stuff that may be added to that unittest: import std.stdio, std.string; void main() { assert(chomp(hello) == hello); assert(chomp(hello\n) == hello); assert(chomp(hello\r\n) == hello); assert(chomp(hello, ) == hello); assert(chomp(hello\n, ) == hello); assert(chomp(hello\r\n, ) == hello); assert(chomp(hello\r\n, ) == hello); assert(chomp(helloxxx, x) == helloxx); } But instead of: if (delimiter == null) Is better to write: if (delimiter.length == 0) Or: if (delimiter == ) See http://d.puremagic.com/issues/show_bug.cgi?id=3889 Bye, bearophile Ahem.. :) Yes, I did miss your answer! How I got fooled by the preview pane and never noticed the scrollbar. I cannot see how your other bug report relates to this though. For chomps part it's just an implementation vs. documentation issue.
Re: Casting away const
On Monday, August 09, 2010 15:01:28 Steven Schveighoffer wrote: Then the author failed to make it const, and it's a bug in the function definition. Casting away const if you don't write is crap, and should be treated as suspiciously as code that writes to const data. I totally agree that the author of the code screwed up. However, sometimes you have to deal with other people's screw ups. And unfortunately, in my experience, a _lot_ of programmers don't bother to write const-correct code, and it causes huge problems for those of us who do. What if calculating the hash is expensive, and you know you don't have to recalculate it, you might cache it as a member of the class. Believe me, if a programmer can do it, he will. Documentation saying don't do this! isn't enough. That's why mutable would be highly desirable, but we don't have it so tough luck for us on that count, I suppose. As for documentation, if the function is const, then no documentation is necessary. They just can't do it (not without casting away constness and going into undefined territory anyway). Personally, I'd say tough luck to the guy who wants to cache the hash by calculating it in toHash(). He can call some other function to cache it, or he could have a non-const version which caches it for cases where the object isn't const, or he could calculate it when something in the class changes (which naturally comes with its own set of pros and cons). From the perspective of logical constness, there is no reason why toHash() can't be const. The one thing that stumps me is why associative arrays allow for const keys with toHash() not being const. If I were to try and write a hashtable implementation myself, I'd have to cast away the constness of the keys to be able to call toHash() on them, which would be _really_ annoying. Maybe that's what associative arrays are doing internally. Personally, I tend to be of the opinion that if a function can be const, it should be const. There are always exceptions of course, but generally I think that functions should be const when possible. It allows for writing const- correct code much more easily (if not just outright makes it possible), and that can reduce the number of mutation bugs that programmers have to deal with. - Jonathan M Davis
Cannot use local xxx as parameter to non-global template.
I'm new, so this is most certainly my fault I guess, but I cannot understand the error message... I wish to slice an array and store the slices in a tuple. auto partitionArray(T)(T[] array, int offset, int len) { auto pre = array[0 .. offset]; auto slice = array[offset .. offset+len]; auto post = array[offset+len .. $]; return Tuple!(pre, slice, post); } unittest { auto val = partitionArray([1,2,3,4], 1, 2); } typecons.d(255): Error: template instance cannot use local 'post' as parameter to non-global template A(U...)
Re: std.string.chomp error
simendsjo: Ahem.. :) Yes, I did miss your answer! How I got fooled by the preview pane and never noticed the scrollbar. No problem, it happens, don't worry. I cannot see how your other bug report relates to this though. My other bug report is about this line in your code: if (delimiter == null) I don't like it :-) Bye, bearophile
Re: std.string.chomp error
On Monday, August 09, 2010 16:59:07 bearophile wrote: simendsjo: Ahem.. :) Yes, I did miss your answer! How I got fooled by the preview pane and never noticed the scrollbar. No problem, it happens, don't worry. I cannot see how your other bug report relates to this though. My other bug report is about this line in your code: if (delimiter == null) I don't like it :-) Bye, bearophile Why, because it should be if(delimiter is null) or just if(!delimiter) - Jonathan M Davis
Re: std.string.chomp error
On 10.08.2010 02:09, Jonathan M Davis wrote: On Monday, August 09, 2010 16:59:07 bearophile wrote: simendsjo: Ahem.. :) Yes, I did miss your answer! How I got fooled by the preview pane and never noticed the scrollbar. No problem, it happens, don't worry. I cannot see how your other bug report relates to this though. My other bug report is about this line in your code: if (delimiter == null) I don't like it :-) Bye, bearophile Why, because it should be if(delimiter is null) or just if(!delimiter) - Jonathan M Davis Hehe.. You're a bit beyond my D level right now. At least I now know null == false and you can do reference is null :)
[OT] What is more readable?
Continuing my what is more readable thread (just shut me up, but I don't always agree with i, j, k etc...): std.string.count: size_t count(string s, string sub) { size_t i; int j; int count = 0; for (i = 0; i s.length; i += j + sub.length) { j = indexOf(s[i .. s.length], sub); if (j == -1) break; count++; } return count; } size_t count(string s, string sub) { int result = 0; int subStart = 0; for (size_t restStart = 0; restStart s.length; restStart += subStart + sub.length) { auto rest = s[restStart .. $]; subStart = indexOf(rest, sub); bool notFound = (subStart == -1); if (notFound) break; result++; } return result; }
More constants in std.string?
\r and \n is used many times throughout std.string (and probably other modules like file). I assume defining constants were considered: const CR = '\r'; const LF = '\n'; So why isn't constants used instead?
Re: [OT] What is more readable?
On Monday, August 09, 2010 17:20:07 simendsjo wrote: Continuing my what is more readable thread (just shut me up, but I don't always agree with i, j, k etc...): Personally, I think that i is just fine in many cases where it's quite clear what you're doing. e.g. the standard for loop: for(size_t i = 0; i a.length; ++i) //whatever we do with a[i]... foreach does reduce how often that sort of thing is necessary though. However, once you get beyond i, and maybe j, it just gets confusing (not to mention the fact that i and j look a fair bit alike). So, personally, I avoid going beyond i, and I don't use i unless it's quite clear what I'm doing. Other than that, I find clearly named variables make the code much easier to read and understand - especially if someone else wrote the code, or you haven't read it in a while. - Jonathan M Davis
Re: More constants in std.string?
On Monday, August 09, 2010 17:24:47 simendsjo wrote: \r and \n is used many times throughout std.string (and probably other modules like file). I assume defining constants were considered: const CR = '\r'; const LF = '\n'; So why isn't constants used instead? Well, what would that really save or help? They're totally unambiguous and easily typed with the keyboard. Not to mention, if you were going to do that, you'd probably define them like so enum CR = \r; enum LF = \n; Using enum for manifest constants is the more typical way to do it in D (it also forces compile-time evaluation of their value), and we want to avoid using individual chars or wchars, so pretty much all string-related functions take strings even if you'd think that they'd take a character of some kind (though if they were to take a character type, it would have to be dchar). In any case, the values for these constants never change regardless of the machine - unlike something like path.sep which indicates the path separator for the machine and changes depending on which machine you compile on. For it to be worth making \r and \n constants, you have to gain something from it, and I don't think that there's much to be gained. Not to mention, you can always make more constants, and you have to stop somewhere, so you're always going to find something that _could_ be a constant and isn't. - Jonathan M Davis
std.string.translate using initializing twice?
translate does this: bool[256] deltab; // this would make all values of deltab false as bool.init == false, right? deltab[] = false; Isn't this just initializing all values of deltab to false twice..? And my Is this more readable? Original: string translate(string s, in string transtab, in string delchars) in { assert(transtab.length == 256); } body { char[] r; int count; bool[256] deltab; deltab[] = false; foreach (char c; delchars) { deltab[c] = true; } count = 0; foreach (char c; s) { if (!deltab[c]) count++; //printf(s[%d] = '%c', count = %d\n, i, s[i], count); } r = new char[count]; count = 0; foreach (char c; s) { if (!deltab[c]) { r[count] = transtab[c]; count++; } } return assumeUnique(r); } More readable?: string translate(string s, in string transtab, in string delchars) in { assert(transtab.length == 256); } body { // Mark characters to delete bool[256] deltab; foreach (char c; delchars) deltab[c] = true; // Count characters to translate int numToTranslate; foreach (char c; s) { if (!deltab[c]) numToTranslate++; } char[] result = new char[numToTranslate]; // Translate int translateIndex = 0; foreach (char c; s) { bool mustTranslate = !deltab[c]; if (mustTranslate) { result[translateIndex] = transtab[c]; translateIndex++; } } return assumeUnique(result); }
Re: [OT] What is more readable?
On 10.08.2010 02:40, Jonathan M Davis wrote: On Monday, August 09, 2010 17:20:07 simendsjo wrote: Continuing my what is more readable thread (just shut me up, but I don't always agree with i, j, k etc...): Personally, I think that i is just fine in many cases where it's quite clear what you're doing. e.g. the standard for loop: for(size_t i = 0; i a.length; ++i) //whatever we do with a[i]... foreach does reduce how often that sort of thing is necessary though. However, once you get beyond i, and maybe j, it just gets confusing (not to mention the fact that i and j look a fair bit alike). So, personally, I avoid going beyond i, and I don't use i unless it's quite clear what I'm doing. Other than that, I find clearly named variables make the code much easier to read and understand - especially if someone else wrote the code, or you haven't read it in a while. - Jonathan M Davis I also use i in my for loops. Always! But I still find it difficult to understand when there are more than one index in use. The thing here is that I couldn't understand the function top to bottom.. j was used both by the incrementer in the for loop, in the indexOf and the if statement. I had to get to the indexOf before I could understand what j was. Of course, I'm just pointing out very small areas of potential improvement as I've only covered 5% of the spec and 1% of the stdlib :)
Re: std.string.translate using initializing twice?
On Monday, August 09, 2010 17:45:07 simendsjo wrote: translate does this: bool[256] deltab; // this would make all values of deltab false as bool.init == false, right? deltab[] = false; Isn't this just initializing all values of deltab to false twice..? I believe that you are correct and that the array is getting set twice. [snip]... I confess that it's entirely irrational on my part given that D is smart enough that a post-increment where the temporary is not used should be just as efficient as a pre-increment (even in the face of operator overloading - unlike C++), but it always makes me cringe to see post-increments where a pre-increment would do... - Jonathan M Davis
Re: More constants in std.string?
On 10.08.2010 02:46, Jonathan M Davis wrote: On Monday, August 09, 2010 17:24:47 simendsjo wrote: \r and \n is used many times throughout std.string (and probably other modules like file). I assume defining constants were considered: const CR = '\r'; const LF = '\n'; So why isn't constants used instead? Well, what would that really save or help? They're totally unambiguous and easily typed with the keyboard. Not to mention, if you were going to do that, you'd probably define them like so enum CR = \r; enum LF = \n; Using enum for manifest constants is the more typical way to do it in D (it also forces compile-time evaluation of their value), and we want to avoid using individual chars or wchars, so pretty much all string-related functions take strings even if you'd think that they'd take a character of some kind (though if they were to take a character type, it would have to be dchar). In any case, the values for these constants never change regardless of the machine - unlike something like path.sep which indicates the path separator for the machine and changes depending on which machine you compile on. For it to be worth making \r and \n constants, you have to gain something from it, and I don't think that there's much to be gained. Not to mention, you can always make more constants, and you have to stop somewhere, so you're always going to find something that _could_ be a constant and isn't. - Jonathan M Davis I agree. I really don't thing it makes a difference or not.. '\r' is always that symbol no matter if it's a iPhone, embedded device or supercomputer. It's more that it's more error prone to write it than CR (ooops! compiler error!). If I wrote '\e' in a large switch and haven't tested all code paths.. Yes, shame on me, but I really meant \r! A constant gives me an at once. D is all about removing common, stupid programmer errors like I do, right? :) It's just nitpicking and not a big deal at all. I can only remember once I've been bitten by one of these (not in D), but I quickly found the source.
Re: std.string.chomp error
Jonathan M Davis: Why, because it should be if(delimiter is null) or just if(!delimiter) if (delimiter.length == 0) Or if (!delimiter.length) Bye, bearophile
Re: std.string.chomp error
On 10.08.2010 03:08, bearophile wrote: Jonathan M Davis: Why, because it should be if(delimiter is null) or just if(!delimiter) if (delimiter.length == 0) Or if (!delimiter.length) Bye, bearophile Isn't that very different things? You cannot use .length if delimiter is null.
Re: std.string.translate using initializing twice?
On Monday, August 09, 2010 18:03:48 simendsjo wrote: Yeah. Don't remember when, don't remember where, but I too have read that preincrement is faster (PS: I don't know any assembler!). As long as I don't use it in an expression, I always use post-increment as it shouldn't make a difference. post-increment creates a temporary. It's really doing something like T temp = i; ++i; //use temp in the expression with i++ The temporary is useless and pointless if i++ is by itself rather than in an expression. In the case of primitives, the compiler knows enough to optimize out the temporary, but in the case of operator overloading in C++, because pre and post-increment are overloaded separately, it can't know for sure that it's safe to do the optimization, so it doesn't do it, and your code is less efficient. That's why code like for(vectorint::iterator iter = vec.begin(), end = vec.end(); iter != end; iter++) { ... } is so bad. You really need to use ++iter in that case. However, in D, this isn't a problem because pre-increment and post-increment are overloaded by one function and the compiler takes care of whether it should be pre or post when it's used. So, it should be able to do the optimization just fine. But I've programmed in C++ for so long (where it does matter), that I instinctively react negatively to post-increment where a pre-increment will do even in languages like Java (which doesn't have operator overloading) or D where it doesn't matter. I'd argue, that everyone (at least everyone programming in C++) should just be in the habit of using pre-increment except the cases where a post-increment is necessary (then you never have to worry about whether it's less efficient to use post-increment in a particular case), but for whatever reason, new programmers are pretty much always taught post-increment first, and so that's what most programmers are used to using. In reality, it's becoming less relevant as newer languages are designed in a manner than there is no difference in efficiency, but my natural reaction is still very much that post-increment by itself is evil. - Jonathan M Davis
Re: std.string.chomp error
On Monday, August 09, 2010 18:12:11 simendsjo wrote: On 10.08.2010 03:08, bearophile wrote: Jonathan M Davis: Why, because it should be if(delimiter is null) or just if(!delimiter) if (delimiter.length == 0) Or if (!delimiter.length) Bye, bearophile Isn't that very different things? You cannot use .length if delimiter is null. If that's what you're looking for, then the proper thing to do would be to import std.array and do this if(delimiter.empty) It wille handle both null and length == 0 cases. Not to mention, it's much more range-y that way. - Jonathan M Davis
Re: More constants in std.string?
On Monday, August 09, 2010 18:21:21 simendsjo wrote: Yeah, I know. I'm really just pointing out very small things here as I try to learn the language and library. Still.. I do think that static checking is a very good way of eliminating many common bugs. This might have been a bad example. I've coded several non-trivial applications in scripting languages, and more often than not, I _know_ what kind of objects my functions accepts... Why a runtime error when you can have a compile time error? Well, fortunately, D is statically-typed and generally designed to catch bugs at compile time rather than runtime. It doesn't always succeed (dmd omniscient after all), but a lot more errors are going to be found at compile time than runtime than you'd get with many other languages - especially scripting languages which tend to be dynamically typed. - Jonathan M Davis
Re: [OT] Is this more readable, or just way too verbose?
simendsjo wrote: I took splitlines from std.string, which is a simple, short method. S[] splitlines(S)(S s) { size_t istart; auto result = Appender!(S[])(); foreach (i; 0 .. s.length) { immutable c = s[i]; if (c == '\r' || c == '\n') { result.put(s[istart .. i]); istart = i + 1; if (c == '\r' i + 1 s.length s[i + 1] == '\n') { i++; istart++; } } } if (istart != s.length) { result.put(s[istart .. $]); } return result.data; } I guess it takes less than 30 seconds to fully understand this method. Then I rap.. I mean refactored it to this: S[] mysplitlines(S)(S s) { const CR = '\r'; const LF = '\n'; size_t istart; auto result = Appender!(S[])(); foreach (i; 0 .. s.length) { immutable c = s[i]; immutable isCR = (c == CR); immutable isLF = (c == LF); if (isCR || isLF) { auto line = s[istart .. i]; result.put(line); istart = i + 1; // Might be CRLF. In that case we need to consume LF too if (isCR) { immutable hasMoreCharacters = (i + 1 s.length); immutable nextIsLF = hasMoreCharacters (s[i + 1] == LF); immutable isCRLF = isCR nextIsLF; if (isCRLF) { i++; istart++; } } } } immutable lineNotEmpty = (istart != s.length); if (lineNotEmpty) { auto lastLine = s[istart .. $]; result.put(lastLine); } return result.data; } Yes, I'm reading some books now and don't have much experience :) It went from a small 26 line, very readable function to 48 lines (85% increase!) with many more temporary variables.. So... Do you think this kind of code is (more) readable, or just way too verbose and doing more harm than good? The CR and LF constants are a bit too much, probably because they don't really abstract over the literals which I can actually parse faster. The isCR and isLF are nice however. Taking it a step further: bool canSplit = inPattern(c,\r\n); if (canSplit) { ... You have increased the nesting of ifs to 3 inside a for-loop. Personally I don't read deep nesting very well. To go for readability I would use a small function for the entire expression: if( s[i..$].startsWithCRLF() ) // same as startsWithCRLF(s[i..$]) { i++; istart++; } or use std.algorithm: if ( s[i..$].startsWith(\r\n) ) And will the compiler generate slower code, or should the optimizer be able to inline the temporaries? I don't think it matters much, but you can only tell by testing. There is a benchmark function (called benchmark iirc) somewhere in phobos to start with and dmd has a builtin profiler too.
What is the term for a function that can be CTFEed?
We have pure functions, member functions, static functions and global functions; but what kind of function can always be used with CTFE? -- ... IXOYE
Re: What is the term for a function that can be CTFEed?
Hello BCS, We have pure functions, member functions, static functions and global functions; but what kind of function can always be used with CTFE? Compile Time Evaluable Function = CTEF? (sounds like CDEF; so testing many minor variant of one you get AB CTEF testing :b ) Or not. -- ... IXOYE
Re: What is the term for a function that can be CTFEed?
On Monday 09 August 2010 21:18:42 BCS wrote: We have pure functions, member functions, static functions and global functions; but what kind of function can always be used with CTFE? Haven't we typical called them CTFE or CTFEable functions? - Jonathan M Davis