#[ are there people paying attention to these issues on other mailing lists? ]
= on Compact structs revision 1, initial posting What functions serialize/deserialize to the C view? If these are to be member functions, they would be applicable only if the struct is compact, and erroneous to call otherwise. It seems like a compact struct ought to have a role supported for that purpose, and to make a compact struct you declare that role. This would then allow the compiler to check at compile-time that all the properties were indeed native types, things also supporting the compact role, or declared to be non-state data. Any class could be forced to be compact regardless of contents if it explicitly supplied the serialization functions. There are some cases where a memory layout can be variable, such as a polymorphic type. The top-level class can read just the first few bytes, determine the correct variant, and create an instance of that. The class would hold a pointer to the variant, and not appear to be a compact struct, except for the custom logic implemented in the pack/unpack functions. A structure may be variable length, having a length-prefixed string or other array, immediately followed by other fields. Having a @list of things as an attribute would normally render it non-compact, but it could have other properties attached that tell it how to read/write that list, in the spirit of IDL. If nothing is available that work in this case, then attaching a custom reader/writer property to just that attribute would do the trick, something sourly missing in systems such as .NET Serialization. class example_record does Compact is finalized { has Str $.name is rw should serialize (:length_prefix(2), :encoding(UTF16), padding => {:char("\0", :strip} ); has int16 $.val is rw; has Str $!presentation_cache; # private, not included in compact struct I/O method presentation () returns Str { unless defined $!presentation_cache { ... # compute it } return $!presentation_cache; } } I'm not entirely sure from S12, so I'd like confirmation on this: The availability of trait 'serialize' is a role nested inside role Compact, so it is available (with this meaning) in this scope. My example uses a mundane int16, which knows to pack/unpack as 2 bytes. But it also has a length-prefixed string, which is explained using the trait, so the class as a whole is still able to pack/unpack. It also has private data, which by default is ignored by the pack/unpack logic and does not interfere with its ability. This is what I envision for a class that can take the place of pack/unpack in a declarative way. I've used pack/unpack for disk-based records and wished that the P5 ability was extensible to my own codes to go with already-defined packable structures. I've also used .NET serialization and found its declarative ability to be lacking to the point where it is often easier to write the function from scratch. Meanwhile, how do I use it? my Buf $temp = $record; $stream.print ($temp); $stream.print (Buf $record); That is a bit baroque. Two issues here: is 'print' still the only way to output? I think 'print' would convert all arguments to string form, so printing an int16 would format the number into text. It also deals with encoding issues. Printing a Buf would seem to turn that Buf back into a Str using all the rules set up for that. So how about a binary output function, 'write'? It will imply binary output, so knowing this can help hide the differences between text/binary on platforms that have it. It will convert its arguments to Buf by default. $stream.write ($record); # just what I need my int16 $x = 42; $stream.write ($x); # emits 2 bytes, exactly as stored in the primitive $stream.print ($x); # emits characters "4" and "2" in the proper encoding So as mentioned at the start of this muse, where do the functions live? It is stated that the type name used as a listop is a conversion function. Is that special syntax that knows to look for some way to accomplish that? I'll proceed on this assumption, and basic C++ ideas as a strawman, that it looks for things in each of the two classes (coming and going) and built-in rules, perhaps a chain of things. Suppose that one of the places it looks is multi conversion:<Buf> () { ... } that can take adjectives to control the conversion, or additional positional arguments. This is supplied by the Compact role, whose implementation handles common adverbs and invariant logic. But it calls another function, pack, for the basic packing work. The version supplied with the Compact role would know about primitive types and to recurse on other Compact items, and iterate over the contents of the class. To do something different, a class can write its own pack function with the required signature to knock-out the default version in the role. class VLI<2.0.1 cpan:DLUGOSZ> does Compact { # implements packing/unpacking as described in <http://www.dlugosz.com/ZIP2/VLI.html> has Int $.value is rw; multi pack (*%adverbs) returns Buf { ... respects standard signed/unsigned option, supports unique options for encoding variations } } # end class VLI That is an example where my "Compact"ness can clearly be seen as a pack/unpack format. Other examples would be structures that appear in the Win32 API, that I can discuss if necessary. Now something I've learned from doing .NET serialization (XML as it happens, but that does not matter to the issue). Here I have an Int, that is a perfectly ordinary Int like any other except for its serialization logic. I can use it in a larger class to make it serialize how I want. But to access the value in that class, I have an extra layer of indirection. class C does Compact is rw { has int32 $x; has VLI $y; } my C $c; # for a Compact class, empty prototype is not undef but default values $c.x= 5; # OK $c.y.value = 1234567812345678; # yuck I'd really like to attach the serialization semantics class to the Int declared in the outer class, where that semantics class does not contain the data itself. class VLI<2.0.1 cpan:DLUGOSZ> does Compact::helper { # implements packing/unpacking as described in <http://www.dlugosz.com/ZIP2/VLI.html> multi pack (Int value, *%adverbs) returns Buf { ... respects standard signed/unsigned option, supports unique options for encoding variations } } # end class VLI class C does Compact is rw { has int32 $x; has Int $y is VLI; } Finally, different kinds of serialization can use similar mechanisms, and more than one can be applied to the same class and all the traits/properties/roles should play nice with each other. Such combined classes should also cascade.