digitalmars.D.learn - Understand typeof trick
- Joakim =?UTF-8?B?QnLDpG5uc3Ryw7Zt?= (35/35) Dec 25 2015 Hello,
- anonymous (26/58) Dec 25 2015 Yup, and then the resulting function is called with arguments
- Joakim =?UTF-8?B?QnLDpG5uc3Ryw7Zt?= (8/18) Dec 25 2015 Ahh, I missed this.
- Adam D. Ruppe (23/23) Dec 25 2015 Well, what I'd really want to document here's isn't necessarily
Hello, In http://forum.dlang.org/post/ojawnpggfaxevqpmrdww forum.dlang.org Adam uses findSkip as an example and especially points out the "D idiom with is/typeof". I'm not quite sure I understand it correctly. Please correct me if I have misunderstood anything regarding the idiom. findSkip: bool findSkip (alias pred = "a == b", R1, R2) (ref R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2 && is( [C] typeof( [B] binaryFun!pred( [A] haystack.front, needle.front)))); [A] Nothing special. findSkip's pred is passed on to binaryFun. binaryFun's constraints thus apply to findSkip's pred. [B] Evaluates to the function type "constructed" by binaryFun. [C] The is expression is true if A->B is valid "code". It is used to convert any compiler errors to "false" (thus the constraint wouldn't be fulfilled). Question: I guess that binaryFun is used in the implementation of findSkip. The reason for using this type of idiom is to avoid "compilation errors" to occur in the implementation when pred/R1/R2 is "funky". It "confuses" the user. The idiom is thus used to move errors to the call site? "D idiom: constraint error at call site"?
Dec 25 2015
On 25.12.2015 13:10, Joakim Brännström wrote:In http://forum.dlang.org/post/ojawnpggfaxevqpmrdww forum.dlang.org Adam uses findSkip as an example and especially points out the "D idiom with is/typeof". I'm not quite sure I understand it correctly. Please correct me if I have misunderstood anything regarding the idiom. bool findSkip (alias pred = "a == b", R1, R2) (ref R1 haystack, R2 needle) if (isForwardRange!R1 && isForwardRange!R2 && is( [C] typeof( [B] binaryFun!pred( [A] haystack.front, needle.front)))); [A] Nothing special. findSkip's pred is passed on to binaryFun. binaryFun's constraints thus apply to findSkip's pred.Yup, and then the resulting function is called with arguments `haystack.front, needle.front`. The template instantiation, and the function call can fail compilation (more precisely: semantic analysis). In that case, A is marked as being "broken".[B] Evaluates to the function type "constructed" by binaryFun.Almost. It evaluates to the type of the expression. The expression is a function call, so typeof evaluates to the return type of the generated function. If A has been marked broken, then B does not become a proper type, and it's marked "broken" as well.[C] The is expression is true if A->B is valid "code".It's true if the argument, i.e. B, is a proper type. In particular, B must not be marked "broken". If B is "broken", then C is false. Any error messages that would usually be printed for the broken A/B are suppressed.It is used to convert any compiler errors to "false" (thus the constraint wouldn't be fulfilled).Yes, but be aware that this only works on semantic errors, not on syntax errors. For example, `is(foo())` and `is(typeof(foo(); bar();))` don't give you false, but they error out in the syntax checking phase. That second one leads us to the longest form of the is-typeof idiom: `is(typeof({foo(); bar();}))`. Wrapping the code in a delegate so that it's an expression, which can be passed to typeof.Question: I guess that binaryFun is used in the implementation of findSkip.Yeah, the constraint wouldn't make sense otherwise.The reason for using this type of idiom is to avoid "compilation errors" to occur in the implementation when pred/R1/R2 is "funky". It "confuses" the user. The idiom is thus used to move errors to the call site? "D idiom: constraint error at call site"?I think Adam meant just the is(typeof(...)) thing itself, regardless of where it appears. Constraints are used to reject bad instantiations early on, yes. They're also used to distinguish different template "overloads".
Dec 25 2015
On Friday, 25 December 2015 at 14:55:04 UTC, anonymous wrote:On 25.12.2015 13:10, Joakim Brännström wrote:Ahh, I missed this. The subtle difference between: int fun(uint x) { return 1; } pragma(msg, typeof(fun)); // -> int(uint x) pragma(msg, typeof(fun()); // -> int[B] Evaluates to the function type "constructed" by binaryFun.Almost. It evaluates to the type of the expression. The expression is a function call, so typeof evaluates to the return type of the generated function.That second one leads us to the longest form of the is-typeof idiom: `is(typeof({foo(); bar();}))`. Wrapping the code in a delegate so that it's an expression, which can be passed to typeof.Nice, didn't know that was possible. I'll remember that. Thank you for the detailed answer.
Dec 25 2015
Well, what I'd really want to document here's isn't necessarily the nitty-gritty of the idiom and why it is used (that's a thing for api authors, but these docs are targeted at api consumers), but more just what it actually means at a glance. That line of code simply means "pred must be a function that takes two arguments of the same type as the front of needle and haystack" The binaryFun helper means you can pass your own function, callable object, or string! The string is one of those "a == b" style things you sometimes see in Phobos. I could write on that line of code for probably a full page from several perspectives - there's quite a lot going on there. But the user of findSkip, when reading that doc, wants to simply know that constraint is about the predicate function, that it must take those arguments. Once you get used to the pattern, you'll know what it means, but first-time readers would surely appreciate a translation right there... and examples of what kind of compiler errors will result if you make a mistake. (And I think it also must return bool, though the constraint doesn't say that... nor does the prose... nor do any of the examples get into it. Gah, so either I'm wrong or that's an undocumented requirement. is(typeof()) could check the return value though.)
Dec 25 2015