Thread overview
Subtyping with alias this
Aug 17, 2020
novice3
Aug 17, 2020
H. S. Teoh
Aug 18, 2020
novice3
Aug 18, 2020
H. S. Teoh
Aug 18, 2020
novice3
August 17, 2020
Hello.
I need subtype uint to store ipv4 address.
It should be like ordinary uint,
except conversion to string with %s format.

My try  https://run.dlang.io/is/fwTc0H  failed on last assert:

```
struct IpV4Address
{
  private uint ip;
  alias ip this;

  string toString()
  {
    import std.conv: to;
    return to!string((ip >>> 24) & 0xFF) ~ "." ~
           to!string((ip >>> 16) & 0xFF) ~ "." ~
           to!string((ip >>> 8) & 0xFF) ~ "." ~
           to!string(ip & 0xFF);
  }
}
void main()
{
  import std.format: format;
  IpV4Address x;
  x = 0x01020304;  // 1.2.3.4
  assert( x ==  0x01020304 );
  assert( format("%s", x) == "1.2.3.4" );
  assert( format("%x", x) == "01020304" );  // FAILED
  /+
std.format.FormatException@/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(4065): Expected '%s' format specifier for type 'IpV4Address'
  +/
}
```

Is my goal (subtype should be normal uint, but with pretty to-string conversion) possible?

Thanks.
August 17, 2020
On Mon, Aug 17, 2020 at 02:29:47PM +0000, novice3 via Digitalmars-d-learn wrote: [...]
> ```
> struct IpV4Address
> {
>   private uint ip;
>   alias ip this;
> 
>   string toString()
>   {
>     import std.conv: to;
>     return to!string((ip >>> 24) & 0xFF) ~ "." ~
>            to!string((ip >>> 16) & 0xFF) ~ "." ~
>            to!string((ip >>> 8) & 0xFF) ~ "." ~
>            to!string(ip & 0xFF);
>   }

What you need is to create an overload of toString that takes a FormatSpec parameter, so that you can decide what should be output for which format spec.  Something along these lines:

	string toString(W,Char)(W sink, FormatSpec!Char fmt) {
		if (fmt.spec == "s")
			return to!string((ip >>> 24) & 0xFF) ~ "." ~
				to!string((ip >>> 16) & 0xFF) ~ "." ~
				to!string((ip >>> 8) & 0xFF) ~ "." ~
				to!string(ip & 0xFF);
		else
			// Fallback to usual uint-formatting
			return format("%s", ip);
	}


T

-- 
We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare.  Now, thanks to the Internet, we know this is not true. -- Robert Wilensk
August 18, 2020
On Monday, 17 August 2020 at 14:43:27 UTC, H. S. Teoh wrote:
> What you need is to create an overload of toString that takes a FormatSpec parameter, so that you can decide what should be output for which format spec.  Something along these lines:

Sorry, i can't make it works.
I tried ti read format.d, but it too complex for me.

The problem is:
if i use fmt.spec in overloaded toString(),
when i get error "phobos/std/format.d(2243): Error: no property ip for type onlineapp.IpV4Address"

reduced code https://run.dlang.io/is/Kgbhfd

```
import std.format;

struct IpV4Address
{
  private uint ip;
  alias ip this;

  void toString(W,Char)(W sink, FormatSpec!Char fmt)
  {
    sink(fmt.spec);  // ERROR
    //sink("s");       // OK
  }
}
void main()
{
  IpV4Address x;
  assert( format("%s", x) == "s");
}
```
/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(2243): Error: no property ip for type onlineapp.IpV4Address
/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(1875): Error: template instance std.format.formatValueImpl!(Appender!string, IpV4Address, char) error instantiating
/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(576):        instantiated from here: formatValue!(Appender!string, IpV4Address, char)
/dlang/dmd-nightly/linux/bin64/../../src/phobos/std/format.d(6630):        instantiated from here: formattedWrite!(Appender!string, char, IpV4Address)
onlineapp.d(17):        instantiated from here: format!(char, IpV4Address)

August 17, 2020
On Tue, Aug 18, 2020 at 05:34:58AM +0000, novice3 via Digitalmars-d-learn wrote: [...]
> The problem is:
> if i use fmt.spec in overloaded toString(),
> when i get error "phobos/std/format.d(2243): Error: no property ip for
> type onlineapp.IpV4Address"

Here's a working example:

---------------------------------------------
import std;

struct IpV4Address
{
	private uint ip;
	alias ip this;

	void toString(W,Char)(W sink, FormatSpec!Char fmt)
	{
		if (fmt.spec == 's') {
			// Deal with %s here
			sink.formattedWrite("%d.%d.%d.%d",
				(ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
				(ip >> 8) & 0xFF, ip & 0xFF);
		} else {
			// Everything else
			formatValue(sink, this.ip, fmt);
		}
	}

	// This unittest is to workaround the sillyness that if toString
	// doesn't compile, std.format pretends it doesn't exist and/or
	// the compiler swallows the real error and substitutes it with
	// an irrelevant error that has nothing to do with the real
	// problem.
	unittest
	{
		IpV4Address ip;
		auto app = appender!string;
		ip.toString(app, FormatSpec!char.init);
	}
}

unittest
{
	auto ip = IpV4Address(0x01020304);
	writefln("%s", ip);
	writefln("%x", ip);
	writefln("%d", ip);
}
---------------------------------------------


T

-- 
No! I'm not in denial!
August 18, 2020
On Tuesday, 18 August 2020 at 05:54:16 UTC, H. S. Teoh wrote:
> Here's a working example:

Thank you, it works!