Search code examples
dylan

standard (idiomatic) way of convert an object to string


I tried to print an object of this class:

define class <bill> (<object>)
    slot num :: <string>;
    slot ref :: <string>;
end class <bill>;

I can make a method like say

define method say (bill : <bill>) => ();
    format-out("num:%s\n", bill.num);
    format-out("ref:%s\n", bill.ref);
end method say;

but I want a method to convert the object to <string> that can be used like

format-out("%s\n", bill);

or

format-out("%s\n", as(<string>, bill));

or

format-out("%=\n", bill);

I tried

define method as(type == <string>, bill :: <bill>) 
  => (s :: <string>);
  let result :: <stretchy-vector> = make(<stretchy-vector>);
  add!(result, bill.num);
  add!(result, bill.ref);
  join(result, " ");
end method as;

but with:

format-out("\%s\n", as(<string>,bill)); 

I had this result

Object {<bill>} cannot be converted to class {<class>: <string>}
Object {<bill> 0x1ff8180} cannot be converted to class {class <string> 0x7f5d5c645c00}
Breaking into debugger.
Trace/breakpoint trap

An with this:

format-out("%s\n", bill);

that result:

{<bill> #x00000000025EF1B0}

What I'm doing wrong? What is the standard (idiomatic) way of printing an object?


Solution

  • The idiomatic way to adding support for printing an object is by specializing print-object. But if you want to be able to convert object representation to string, specializing as generic is the way to go, as you did. It works here, so maybe there's a bug somewhere:

    module: bill
    
    define class <bill> (<object>)
      constant slot num :: <string>, init-keyword: num:;
      constant slot ref :: <string>, init-keyword: ref:
    end class <bill>;
    
    define method as(type == <string>, bill :: <bill>) => (s :: <string>);
      join(vector(bill.num, bill.ref), " ");
    end method as;
    
    format-out("%=\n", as(<string>, make(<bill>, num: "1", ref: "a")));
    

    Result:

    $ bill 
    "1 a"