Strange behavior in DWIM with new blob type

Hello there,

For the terminus-store prolog binding, we’ve defined a bunch of custom blob types. Each of them has a proper write function defined (see terminus_store_prolog/blobs.c at c60e785020c048b05d57f8c9e74d4af1756e8f33 · terminusdb/terminus_store_prolog · GitHub).

But now, see the following:

?- open_directory_store('/tmp/foo', Store).
Store = #<store_blob> .

?- writ($Store).
Correct to: "write(������������������⤾"? yes
#<store_blob>
Store = #<store_blob> .

For some reason, DWIM is trying to represent our blob as this weird sequence of characters that is definitely not coming out of our write function.

I thought maybe there’d be a bug with representing blob types in DWIM, but it looks like streams work just fine:

?- open_null_stream(Stream).
Stream = <stream>(0x55bb577df170).

?- writ($Stream).
Correct to: "write(<stream>(0x55bb577df170))"? yes
<stream>(0x55bb577df170)
Stream = <stream>(0x55bb577df170).

Am I doing something wrong in my blob definitions?

All this is with swipl 8.0.3.

static int write_named_graph_blob(void *closure, atom_t a, int flags) {
    IOSTREAM *out = closure;
    char* contents = "#<named_graph>";
    Sfwrite(contents, 1, strlen(contents), out);
    return TRUE;
}

My guess is that you use Sfwrite(), which writes a sequence of bytes and thus the result depends on the encoding. Use e.g., Sfprintf(out, "#<named_graph>"). Of course you can do what you want but the convention is to write <type>(arg, ...) for blobs. What you put in arg, … depends. Typically it makes sense to put some pointer in there, so you know that two blobs are (not) the same. It may also make sense to provide some information about the identity or status of the blob.

Note that the prototype defines the first argument to be of type IOSTREAM* if IOMAGIC is defined, which is the case if you load SWI-Stream.h. If you want to use the stream functions (and you need them here) first include SWI-Stream.h.

Using Sfprintf works, thank you. I still don’t quite get it though. Why does it Sfwrite work properly when using the write/1 predicate, but not in the DWIM correction?

Of course you can do what you want but the convention is to write <type(arg, …)> for blobs.

The #<blob> syntax is a common lisp thing which I accidentally applied here. Following conventions is good so I’ll change it.

However, I notice that the Stream blob uses <type>(arg) format rather than <type(arg)> as you suggest. Which one is better?

Because DWIM does internal serialization. Such internal writes use a buffer typically using the wchar_t encoding, so we do not have to do any recoding.

The first. Thanks. I’ll fix my post.