www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opEquals() non-standard return type

reply Jacob Shtokolov <jacob.100205 gmail.com> writes:
Hi,

I'm trying to check whether it's possible to implement Python's 
SQLAlchemy-like query syntax in D, but I get stuck a bit.

Here is a simple example of what I want to achieve:

```
auto result = User.filter(User.id == 10);
result = User.filter(User.name == "John");
result = User.filter(User.age > 18);
```

Expressions like `User.id == 10`, `User.age > 18`, etc. should 
return a struct instead of a bool (let's call it `struct 
BinaryExpression`).

So I'm making the two versions of opEquals: one returns a 
BinaryExpression, and the second - a boolean value.

However, when I want to use the same expression for the `if` 
operator, the compiler cannot decide what function to call and 
shows an error: "overloads bool(int b) and BinaryExpr!int(int b) 
both match argument list for opEquals".


I'm wondering, is that possible to declare multiple versions of 
opEquals() and evaluate them in the different places depending on 
return type?

Here is my test code to check: https://run.dlang.io/is/yTFHWp
Gist: 
https://gist.github.com/run-dlang/67ec42ca73d56d310e8ae765fabede69

Thanks!
Jan 23 2019
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, January 23, 2019 8:19:06 AM MST Jacob Shtokolov via 
Digitalmars-d-learn wrote:
 Hi,

 I'm trying to check whether it's possible to implement Python's
 SQLAlchemy-like query syntax in D, but I get stuck a bit.

 Here is a simple example of what I want to achieve:

 ```
 auto result = User.filter(User.id == 10);
 result = User.filter(User.name == "John");
 result = User.filter(User.age > 18);
 ```

 Expressions like `User.id == 10`, `User.age > 18`, etc. should
 return a struct instead of a bool (let's call it `struct
 BinaryExpression`).

 So I'm making the two versions of opEquals: one returns a
 BinaryExpression, and the second - a boolean value.

 However, when I want to use the same expression for the `if`
 operator, the compiler cannot decide what function to call and
 shows an error: "overloads bool(int b) and BinaryExpr!int(int b)
 both match argument list for opEquals".


 I'm wondering, is that possible to declare multiple versions of
 opEquals() and evaluate them in the different places depending on
 return type?

 Here is my test code to check: https://run.dlang.io/is/yTFHWp
 Gist:
 https://gist.github.com/run-dlang/67ec42ca73d56d310e8ae765fabede69

 Thanks!
D's operator overloading is specifically designed around the idea that overloaded operators are supposed to act like the operators on the built-in types and that they _not_ be used for building syntax. opEquals is supposed to only return bool. If you attempt to make it return pretty much anything else, you're begging for trouble. But regardless of the specifics of operator overloading in D, D does not support overloading _any_ functions on the return type. Overloading is only done based an a function's arguments. You've declared two overloads with the exact same types for all of their parameters such that they only differ by their return type, and you can't do that in D. - Jonathan M Davis
Jan 23 2019
parent Jacob Shtokolov <jacob.100205 gmail.com> writes:
On Wednesday, 23 January 2019 at 15:28:02 UTC, Jonathan M Davis 
wrote:
 But regardless of the specifics of operator overloading in D, D 
 does not support overloading _any_ functions on the return type.
Thanks!
Jan 23 2019
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 23, 2019 at 03:19:06PM +0000, Jacob Shtokolov via
Digitalmars-d-learn wrote:
 Hi,
 
 I'm trying to check whether it's possible to implement Python's
 SQLAlchemy-like query syntax in D, but I get stuck a bit.
 
 Here is a simple example of what I want to achieve:
 
 ```
 auto result = User.filter(User.id == 10);
 result = User.filter(User.name == "John");
 result = User.filter(User.age > 18);
 ```
[...] The best way to do this is to use a string DSL or a delegate as template argument. For example: auto result = User.filter!q{ User.name == "John" }; or: auto result = User.filter!(u => u.name == "John"); The delegate option will be easier to implement, but the syntax will be slightly more verbose. The string DSL option will give you the best syntax, but then you'll have to implement a compile-time DSL parser. T -- Bare foot: (n.) A device for locating thumb tacks on the floor.
Jan 23 2019
parent Jacob Shtokolov <jacob.100205 gmail.com> writes:
On Wednesday, 23 January 2019 at 17:28:37 UTC, H. S. Teoh wrote:
 The best way to do this is to use a string DSL or a delegate as 
 template argument. For example:

 	auto result = User.filter!q{ User.name == "John" };

 or:

 	auto result = User.filter!(u => u.name == "John");
I didn't know about q{} token strings! This looks very cool for implementing different DSLs. Thank you!
Jan 24 2019
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/23/2019 07:19 AM, Jacob Shtokolov wrote:

 Expressions like `User.id == 10`, `User.age > 18`, etc. should return a
 struct instead of a bool (let's call it `struct BinaryExpression`).
Have you considered 'alias this'? struct BinaryExpr(T) { T left; T right; Op op; bool value() const { final switch (op) with (Op) { case Equals: return left == right; case NotEquals: return left != right; } } alias value this; }
 So I'm making the two versions of opEquals: one returns a
 BinaryExpression, and the second - a boolean value.
Yeah, that can't work. Remove the bool-returning one and your code works with the 'alias this' above. Ali
Jan 23 2019
parent Jacob Shtokolov <jacob.100205 gmail.com> writes:
On Thursday, 24 January 2019 at 00:47:37 UTC, Ali Çehreli wrote:
 Yeah, that can't work. Remove the bool-returning one and your 
 code works with the 'alias this' above.
Wow, this is an amazing workaround! I didn't think about it in that way. It perfectly solves the issue. Thank you!
Jan 24 2019
prev sibling parent Neia Neutuladh <neia ikeran.org> writes:
On Wed, 23 Jan 2019 15:19:06 +0000, Jacob Shtokolov wrote:
 I'm wondering, is that possible to declare multiple versions of
 opEquals() and evaluate them in the different places depending on return
 type?
I looked at this a while ago for similar reasons. It didn't pan out. When you override the comparison operator, you can't distinguish which comparison is overloaded. It takes at least 2^n evaluations of the function to determine all the comparisons, possibly more. (I *think* you can observe the short-circuiting logic as you do those evaluations to determine how each comparison is combined.)
Jan 23 2019