www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opCast'ing strings

reply helxi <brucewayneshit gmail.com> writes:
struct Fraction
{
private:
	int numerator = 1, denominator = 1;
public:
	string opCast(T : string)() const
	{
		import std.conv : to;

		return numerator.to!string() ~ "/" ~ denominator.to!string();
	}
}

void main()
{
	import std.stdio, std.conv;

	Fraction n = Fraction(23, 11);
	writeln(n.to!string(), " ", n.opCast!string);
}



In this program, casting using to does not work as intended 
(returning 23/11) on the struct. However, calling opCast directly 
seems to do the job. Why is that?
Nov 12 2017
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 13 November 2017 at 01:03:17 UTC, helxi wrote:
 In this program, casting using to does not work as intended 
 (returning 23/11) on the struct. However, calling opCast 
 directly seems to do the job. Why is that?
to!string calls a function called `string toString() {}` on the struct, not the cast operator.
Nov 12 2017
parent reply bauss <jj_1337 live.dk> writes:
On Monday, 13 November 2017 at 01:12:59 UTC, Adam D. Ruppe wrote:
 On Monday, 13 November 2017 at 01:03:17 UTC, helxi wrote:
 In this program, casting using to does not work as intended 
 (returning 23/11) on the struct. However, calling opCast 
 directly seems to do the job. Why is that?
to!string calls a function called `string toString() {}` on the struct, not the cast operator.
Which is generally what you want to use anyway and not a cast overload. My rule of thumb (Which can of course differ per preference.) is that cast overload should only be done between the following: struct <-> scalar types class <-> scalar types struct <-> class Any string conversions should always be done with `toString()`. Anything else should not be implemented with casts or conversion methods. An exception of course is creating slices, which is acceptable using `opSlice`, but generally I avoid using something like `opCast` to an array, UNLESS it's an array wrapper, which you most likely won't have in D anyway, because you'd be better off creating a range.
Nov 13 2017
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, November 13, 2017 12:40:39 bauss via Digitalmars-d-learn wrote:
 On Monday, 13 November 2017 at 01:12:59 UTC, Adam D. Ruppe wrote:
 On Monday, 13 November 2017 at 01:03:17 UTC, helxi wrote:
 In this program, casting using to does not work as intended
 (returning 23/11) on the struct. However, calling opCast
 directly seems to do the job. Why is that?
to!string calls a function called `string toString() {}` on the struct, not the cast operator.
Which is generally what you want to use anyway and not a cast overload. My rule of thumb (Which can of course differ per preference.) is that cast overload should only be done between the following: struct <-> scalar types class <-> scalar types struct <-> class Any string conversions should always be done with `toString()`. Anything else should not be implemented with casts or conversion methods. An exception of course is creating slices, which is acceptable using `opSlice`, but generally I avoid using something like `opCast` to an array, UNLESS it's an array wrapper, which you most likely won't have in D anyway, because you'd be better off creating a range.
There's nothing wrong with using opCast to define other conversions - it's generally what std.conv.to is going to use (the other options being alias this and a constructor if the type being converted to has a constructor that would work). It's just that in the case of string, there's a standard function for converting to it other than opCast. The main problem with overloading opCast in general is that doing so unfortunately disables all of the built-in casts, which can be a big problem - though hopefully that gets fixed at some point. https://issues.dlang.org/show_bug.cgi?id=5747 https://issues.dlang.org/show_bug.cgi?id=9249 There's also the argument that using an explicitly named function is clearer - particularly if it's not obvious what converting from one type to another would mean - but those won't work with std.conv.to. So, it depends on what you're trying to do. - Jonathan M Davis
Nov 13 2017