Re: anonymous functions and scope(exit)
On Saturday, 3 July 2021 at 22:04:04 UTC, Luis wrote: scope(exit) it's syntactic sugar for a classic `try {} finally {}` . The documentation says that must be executed. It works if you replace printf() with writeln() or use writeln() after. There must be some buffer issue.
Re: anonymous functions and scope(exit)
On Saturday, 3 July 2021 at 20:46:00 UTC, Steven Schveighoffer wrote: On 7/3/21 4:08 PM, frame wrote: On Saturday, 3 July 2021 at 17:39:18 UTC, Steven Schveighoffer wrote: But in practice, the compiler does not have to clean up anything when an `Error` is thrown. Whether it does or not is defined by the implementation. This should be really mentionend in the docs? "Guard", yeah... Yeah, there isn't a good discussion of the differences between Error and Exception on that page. -Steve On [The D Error Handling Solution](https://dlang.org/spec/errors.html#the_d_error_handling_solution), says : If code detects an error like "out of memory," then an Error is thrown with a message saying "Out of memory". The function call stack is unwound, looking for a handler for the Error. Finally blocks are executed as the stack is unwound. If an error handler is found, execution resumes there. If not, the default Error handler is run, which displays the message and terminates the program. scope(exit) it's syntactic sugar for a classic `try {} finally {}` . The documentation says that must be executed.
Re: anonymous functions and scope(exit)
On Saturday, 3 July 2021 at 17:47:47 UTC, Dennis wrote: On Saturday, 3 July 2021 at 17:20:47 UTC, Luis wrote: scope(exit) inside of a anonymous functions, it's never called. I think the compiler infers the function `nothrow` since you don't throw any `Exception`, only an `Error`. Errors represent unrecoverable bugs, after which the program is in an invalid state, so the compiler is free to exit immediately without caring about destructors or `scope(exit)`. Use `Exception` instead of `Error` if you want the stack to properly unwind. Indeed, this is happening. I can reproduce with this : ```d #!/usr/bin/env dub /+ dub.sdl: dependency "pijamas" version="~>1.1" +/ import core.exception; void main() { import core.stdc.stdio; import pijamas; should(() { printf("Hello\n"); scope(exit) printf("Bye\n"); throw new RangeError("bla bla"); }).Throw!RangeError; auto f = () { printf("Hello\n"); scope(exit) printf("Bye\n"); throw new RangeError("bla bla"); }; f(); } ``` Outputs this : ``` $ f.d Hello Hello core.exception.RangeError@bla bla(20): Range violation source/f.d:20 nothrow void f.main().__lambda2() [0x5647d46a17db] source/f.d:22 _Dmain [0x5647d46a1732] Program exited with code 1 ``` If I change the RangeError, by a Exception, then the scope(exit) it's executed.
Re: anonymous functions and scope(exit)
On 7/3/21 4:08 PM, frame wrote: On Saturday, 3 July 2021 at 17:39:18 UTC, Steven Schveighoffer wrote: But in practice, the compiler does not have to clean up anything when an `Error` is thrown. Whether it does or not is defined by the implementation. This should be really mentionend in the docs? "Guard", yeah... Yeah, there isn't a good discussion of the differences between Error and Exception on that page. -Steve
Re: how much "real-life" code can be marked @safe ?
On Saturday, 3 July 2021 at 16:06:33 UTC, Alexandru Ermicioi wrote: 3. An edge case. Ex: You need to mutate some data and then assume it is immutable in a constructor. Can you give a valid example where that is necessary? The main examples that I can think of either can be `@safe` with the right API, or are motivated by a desire to avoid the GC and/or druntime, thus falling under (1). 4. Functionality that doesn't account for @safe/immutable or any other features when it can in standard library. True, although it's just another example of my point (2). The standard library and druntime are dependencies, too... Take for example array.dup, there is no inout alternative for it, and you're pretty much stuck with trusted code, when you'd like to dup an array that is inout. `inout` is usually just a convenient way to use one implementation to handle mutable, `const` and `immutable` cases. In those rare cases where `inout` itself won't work, it is almost always possible to accomplish the same thing using `template this` or separate overloads: ```D import std.traits : Unqual, CopyConstness; struct A { int*[] arr; this(this This, Arr)(Arr arr) scope pure @safe nothrow if(is(Arr : E[], E) && is(E : CopyConstness!(This, Unqual!E))) { this.arr = arr.dup; } } void main() { A ma = new int*[5]; const(A) ca = new const(int*[3]); const(A) ia = new immutable(int*[4]); } ``` Again, it's certainly not obvious how to do this, or why it is necessary, but it is *possible*. The one exception here is when the array is already typed `inout` before it is passed to the constructor. But, that's an example of (2) since this logic applies transitively throughout the call stack: if you need to call `dup` anywhere, don't erase the constness with `inout`.
Re: anonymous functions and scope(exit)
On Saturday, 3 July 2021 at 17:39:18 UTC, Steven Schveighoffer wrote: But in practice, the compiler does not have to clean up anything when an `Error` is thrown. Whether it does or not is defined by the implementation. This should be really mentionend in the docs? "Guard", yeah...
Re: do we already have sum-modulo-10 algo (aka Luhn's algo) on phobos ?
On Saturday, 3 July 2021 at 17:44:48 UTC, someone wrote: https://en.wikipedia.org/wiki/Luhn_algorithm#Pseudocode_implementation That specific function, in Phobos? no. sum modulo 10? That's just some_var%10 in D. The Wikipedia link ends with a link to RosettaCode: https://rosettacode.org/wiki/Luhn_test_of_credit_card_numbers#D ... this is a pretty nice RC entry, translating Haskell, C, and SPARK all into D. Really shows off D's range of expression.
Re: anonymous functions and scope(exit)
On Saturday, 3 July 2021 at 17:20:47 UTC, Luis wrote: scope(exit) inside of a anonymous functions, it's never called. I think the compiler infers the function `nothrow` since you don't throw any `Exception`, only an `Error`. Errors represent unrecoverable bugs, after which the program is in an invalid state, so the compiler is free to exit immediately without caring about destructors or `scope(exit)`. Use `Exception` instead of `Error` if you want the stack to properly unwind.
Re: anonymous functions and scope(exit)
On Saturday, 3 July 2021 at 17:20:47 UTC, Luis wrote: This is intentional ? ... scope(exit) inside of a anonymous functions, it's never called. ``` $ rdmd --eval 'iota(2).map!((int x) { scope(exit) writeln("got: ", x); return x+1; }).array.writeln' got: 0 got: 1 [1, 2] ``` Conclusion: it's not intentional.
do we already have sum-modulo-10 algo (aka Luhn's algo) on phobos ?
https://en.wikipedia.org/wiki/Luhn_algorithm#Pseudocode_implementation
Re: anonymous functions and scope(exit)
On 7/3/21 1:20 PM, Luis wrote: This is intentional ? ``` should(function void() { auto emptyStack = SimpleStack!int(); scope(exit) emptyStack.free; // <= This is never called emptyStack.reserve(16); emptyStack.top; }).Throw!RangeError; ``` scope(exit) inside of a anonymous functions, it's never called. In principle, it should technically be called. But in practice, the compiler does not have to clean up anything when an `Error` is thrown. Whether it does or not is defined by the implementation. However, it should *always* work if it's an `Exception` and not an `Error`. ```d import std.stdio; void main() { auto f = function void() { scope(exit) writeln("hi"); throw new Exception("boo"); }; f(); } ``` prints "hi" -Steve
Re: anonymous functions and scope(exit)
On Saturday, 3 July 2021 at 17:20:47 UTC, Luis wrote: This is intentional ? ``` should(function void() { auto emptyStack = SimpleStack!int(); scope(exit) emptyStack.free; // <= This is never called emptyStack.reserve(16); emptyStack.top; }).Throw!RangeError; ``` scope(exit) inside of a anonymous functions, it's never called. Please provide an example code. What lib is this? Normally scope(exit) works also for anonymous functions.
anonymous functions and scope(exit)
This is intentional ? ``` should(function void() { auto emptyStack = SimpleStack!int(); scope(exit) emptyStack.free; // <= This is never called emptyStack.reserve(16); emptyStack.top; }).Throw!RangeError; ``` scope(exit) inside of a anonymous functions, it's never called.
Re: how much "real-life" code can be marked @safe ?
On Friday, 2 July 2021 at 22:08:31 UTC, tsbockman wrote: (Responding out of order:) On Friday, 2 July 2021 at 00:26:52 UTC, someone wrote: But when you start attempting to declare @safe chunks of code that actually DO things ... well, it seems end-of-the-story. If you find yourself unable to get real work done in `@safe` code, this is almost certainly a sign of one of the following problems: 0) You don't fully understand the purpose and valid use of any or all of the `@trusted`, `inout`, `scope`, and `return` annotations. 1) Your code is avoiding use of the garbage collector, and/or does not have `-dip1000` enabled. (`@safe` is still quite useful without the garbage collector, but even with `-dip1000` you'll still need a lot of `@trusted` code.) 2) You have at least one dependency that isn't correctly designed for use with `@safe`. I'd add: 3. An edge case. Ex: You need to mutate some data and then assume it is immutable in a constructor. 4. Functionality that doesn't account for @safe/immutable or any other features when it can in standard library. Take for example array.dup, there is no inout alternative for it, and you're pretty much stuck with trusted code, when you'd like to dup an array that is inout. manual. Although these two should be on the lowest place in this list by priority.
Re: How to select the regex that matches the first token of a string?
On Saturday, 3 July 2021 at 09:28:32 UTC, user1234 wrote: On Saturday, 3 July 2021 at 09:05:28 UTC, vnr wrote: Hello, I am trying to make a small generic lexer that bases its token analysis on regular expressions. The principle I have in mind is to define a token type table with its corresponding regular expression, here is the code I currently have: [...] storing the regex in a token is an antipattern. Thank you for the answer, I know it's not clean, I'll modify my code to define a token type table with their regular expression and define a token type table with what has match; the former defining the lexer, the latter being the result of the latter. But for now and to keep it simple, I did everything in one.
Re: How to select the regex that matches the first token of a string?
On Saturday, 3 July 2021 at 09:05:28 UTC, vnr wrote: Hello, I am trying to make a small generic lexer that bases its token analysis on regular expressions. The principle I have in mind is to define a token type table with its corresponding regular expression, here is the code I currently have: [...] storing the regex in a token is an antipattern.
How to select the regex that matches the first token of a string?
Hello, I am trying to make a small generic lexer that bases its token analysis on regular expressions. The principle I have in mind is to define a token type table with its corresponding regular expression, here is the code I currently have: ```d import std.regex; /// ditto struct Token { /// The token type string type; /// The regex to match the token Regex!char re; /// The matched string string matched = null; } /// Function to find the right token in the given table Token find(Token[] table, const(Captures!string delegate(Token) pure @safe) fn) { foreach (token; table) if (fn(token)) return token; return Token("", regex(r"")); } /// The lexer class class Lexer { private Token[] tokens; /// ditto this(Token[] tkns = []) { this.tokens = tkns; } override string toString() const { import std.algorithm : map; import std.conv : to; import std.format : format; return to!string (this.tokens.map!(tok => format("(%s, %s)", tok.type, tok.matched))); } // Others useful methods ... } /// My token table static Token[] table = [ Token("NUMBER", regex(r"(?:\d+(?:\.\d*)?|\.\d+)")) , Token("MINS", regex(r"\-")) , Token("PLUS", regex(r"\+")) ]; /// Build a new lexer Lexer lex(string text) { Token[] result = []; while (text.length > 0) { Token token = table.find((Token t) => matchFirst(text, t.re)); const string tmatch = matchFirst(text, token.re)[0]; result ~= Token(token.type, token.re, tmatch); text = text[tmatch.length .. $]; } return new Lexer(result); } void main() { import std.stdio : writeln; const auto l = lex("3+2"); writeln(l); } ``` When I run this program, it gives the following sequence: ``` ["(NUMBER, 3)", "(NUMBER, 2)", "(NUMBER, 2)"] ``` While I want this: ``` ["(NUMBER, 3)", "(PLUS, +)", "(NUMBER, 2)"] ``` The problem seems to come from the `find` function which returns the first regex to have match and not the regex of the first substring to have match (I hope I am clear enough ). I'm not used to manipulating regex, especially in D, so I'm not sure how to consider a solution to this problem. I thank you in advance for your help.