www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Subtyping with alias this

reply novice3 <sorryno em.ail> writes:
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.
Aug 17 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
Aug 17 2020
parent reply novice3 <sorryno em.ail> writes:
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)
Aug 17 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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!
Aug 17 2020
parent novice3 <sorryno em.ail> writes:
On Tuesday, 18 August 2020 at 05:54:16 UTC, H. S. Teoh wrote:
 Here's a working example:
Thank you, it works!
Aug 17 2020