Re: How do I print a structure?

[email protected] (ToddAndMargo via perl6-users) Sat, 12 Apr 2025 11:56:07 -0700
Newsgroups perl.perl6.users
Message-ID <[email protected]>
On 4/12/25 10:14 AM, Tirifto wrote:
> Hello!
> 
> Both `print` and `say` convert their argument to a string, but they do 
> so by calling different methods on the argument. `print` calls the 
> method `.Str`, while `say` calls the method `.gist`. On custom classes 
> (like your PartitionClass), calling `.Str` will only return the object’s 
> identifier by default, but calling `.gist` (or `.raku`) will return code 
> you can run to re-create the object. So to get the same output with 
> `print` like you did with `say`, only without the newline, you can do 
> `print $Partition.gist` or `print $Partition.raku`. (`.gist` might not 
> show the entire code if the text gets too long, so you might prefer to 
> use `.raku`.)
> 
> Calling `.kv` doesn’t work, because objects (/unlike/ maps / tables) 
> aren’t transparent structures that you can see the insides of. From the 
> perspective of OOP, objects are opaque, and the only proper way to look 
> inside is by calling their methods. So if you want to be able to see all 
> of the object’s attributes, you should *give the class a method* that 
> will return all of the object’s attributes in some form. You could 
> override the `.Str` or `.gist` methods if you simply want to print the 
> attributes in a nice form, or you could override the `.kv` method if you 
> might want to do something else with them. Here’s an example:
> 
>     [0] > class PartitionClass{
>         has Str $.DeviceID          is rw;
>         has Str $.VolumeName        is rw;
>         has Str $.ProviderName      is rw;
>         has Str $.UNC_BackupPath    is rw;
>         has Int $.DriveType         is rw;
>         has Str $.DriveTypeStr      is rw;
>         has Int $.FreeSpace         is rw;
>         has Int $.Size              is rw;
>         has Int $.PercentUsed       is rw;
>         has Int $.PercentRemaining  is rw;
> 
>         #| Return a list of pair objects: (Attribute name => Attribute
>     value)
>         method pairs(--> Iterable) {
>             :$.DeviceID, :$.VolumeName, :$.ProviderName,
>             :$.UNC_BackupPath, :$.DriveType, :$.DriveTypeStr,
>             :$.FreeSpace, :$.Size, :$.PercentUsed, :$.PercentRemaining;
>         }
> 
>         #| Return a sequence of attribute names and values interleaved.
>         method kv(--> Iterable) {
>             $.pairs.map({ .kv }).flat;
>         }
> 
>         #| Return a string presenting all attributes on a single line.
>         method Str(--> Str) {
>             $.pairs.map({ .key ~ “: ” ~ .value }).join(“, ”) ~ “.”;
>         }
>     }
>     (PartitionClass)
> 
>     [1] > my $Partition = PartitionClass.new(
>         DeviceID         => "",
>         VolumeName       => "",
>         ProviderName     => "",
>         UNC_BackupPath   => "",
>         DriveType        => 0,
>         DriveTypeStr     => "Unknown",
>         FreeSpace        => 0,
>         Size             => 0,
>         PercentUsed      => 0,
>         PercentRemaining => 100
>     );
>     PartitionClass.new(DeviceID => "", VolumeName => "", ProviderName =>
>     "", UNC_BackupPath => "", DriveType => 0, DriveTypeStr => "Unknown",
>     FreeSpace => 0, Size =>
>     0, PercentUsed => 0, PercentRemaining => 100)
> 
>     [2] > for $Partition.kv -> $i, $j { print "i <$i>   j <$j>\n" }
>     i <DeviceID>   j <>
>     i <VolumeName>   j <>
>     i <ProviderName>   j <>
>     i <UNC_BackupPath>   j <>
>     i <DriveType>   j <0>
>     i <DriveTypeStr>   j <Unknown>
>     i <FreeSpace>   j <0>
>     i <Size>   j <0>
>     i <PercentUsed>   j <0>
>     i <PercentRemaining>   j <100>
> 
>     [2] > print $Partition ~ "\n";
>     DeviceID: , VolumeName: , ProviderName: , UNC_BackupPath: ,
>     DriveType: 0, DriveTypeStr: Unknown, FreeSpace: 0, Size: 0,
>     PercentUsed: 0, PercentRemaining: 100.
> 
>     [2] > say $Partition;
>     PartitionClass.new(DeviceID => "", VolumeName => "", ProviderName =>
>     "", UNC_BackupPath => "", DriveType => 0, DriveTypeStr => "Unknown",
>     FreeSpace => 0, Size =>
>     0, PercentUsed => 0, PercentRemaining => 100)
> 
> Of course, both the code and the formatting of the output could be 
> improved. :-)
> 
> You could also ask Raku to list all of the object’s attributes and then 
> find each of their values for your object. This pretty much violates the 
> principles of OOP, so it might not be something you want your programs 
> to rely on, but if you just need to inspect an object’s internal state 
> for your personal use, it’s probably fine! An example:
> 
>     [2] > for $Partition.^attributes { say “{.name}: {.get_value:
>     $Partition}” }
>     $!DeviceID:
>     $!VolumeName:
>     $!ProviderName:
>     $!UNC_BackupPath:
>     $!DriveType: 0
>     $!DriveTypeStr: Unknown
>     $!FreeSpace: 0
>     $!Size: 0
>     $!PercentUsed: 0
>     $!PercentRemaining: 100
> 
> If there are better ways, I’m afraid I don’t know of them. Hope this 
> helps, though! ^ ^
> // Tirifto
> 
> On 11. 04. 25 8:19, ToddAndMargo via perl6-users wrote:
>> Hi All,
>>
>> I am not having any luck printing the values of a OOP
>> structure, except for printing them one at a time.  I
>> can get it to messily print with `say`, but I want to
>> do it with `print` so I can control the line feeds,
>> comments, etc..
>>
>> What am I doing wrong?
>>
>> Many thanks,
>> -T
>>
>>
>> [0] > class PartitionClass{
>>     has Str $.DeviceID          is rw;
>>     has Str $.VolumeName        is rw;
>>     has Str $.ProviderName      is rw;
>>     has Str $.UNC_BackupPath    is rw;
>>     has Int $.DriveType         is rw;
>>     has Str $.DriveTypeStr      is rw;
>>     has Int $.FreeSpace         is rw;
>>     has Int $.Size              is rw;
>>     has Int $.PercentUsed       is rw;
>>     has Int $.PercentRemaining  is rw;
>> }
>> (PartitionClass)
>>
>>
>> [1] > my $Partition = PartitionClass.new(
>>     DeviceID         => "",
>>     VolumeName       => "",
>>     ProviderName     => "",
>>     UNC_BackupPath   => "",
>>     DriveType        => 0,
>>     DriveTypeStr     => "Unknown",
>>     FreeSpace        => 0,
>>     Size             => 0,
>>     PercentUsed      => 0,
>>     PercentRemaining => 100
>> );
>> PartitionClass.new(DeviceID => "", VolumeName => "", ProviderName => 
>> "", UNC_BackupPath => "", DriveType => 0, DriveTypeStr => "Unknown", 
>> FreeSpace => 0, Size => 0, PercentUsed => 0, PercentRemaining => 100)
>>
>>
>> [2] > for $Partition.kv -> $i, $j { print "i <$i>   j <$j>\n" }
>> i <0>   j <PartitionClass<4875316684000>>
>>
>>
>> [2] > print $Partition ~ "\n";
>> PartitionClass<4875316684000>
>>
>>
>> [2] > say $Partition;
>> PartitionClass.new(DeviceID => "", VolumeName => "", ProviderName => 
>> "", UNC_BackupPath => "", DriveType => 0, DriveTypeStr => "Unknown", 
>> FreeSpace => 0, Size => 0, PercentUsed => 0, PercentRemaining => 100)
>>


Hi Tirifto,

What a ton of work you put into that response.  Very,
very much appreciated!

And yes, it does help. I will be copying your response
down into my keepers.

LOVE oop's!

-T