swipl-devel icon indicating copy to clipboard operation
swipl-devel copied to clipboard

Missing from SWI-Prolog.h: wchar_t equivalent of PL_put_atom_nchars()

Open kamahen opened this issue 3 years ago • 10 comments

I can do the following in C++

if ( !(ref_ = PL_new_term_ref()) ||
     !PL_put_atom_nchars(ref_, text.size(), text.data()) )
   throw PlResourceError();

but for wchar_t* or std:wstring, it seems that there's no PL_put_XXX() and instead I must do PL_unify_wchars() ... is this deliberate? (And,therefore, PL_put_atom_nchars() is deprecated and shouldn't be used?):

if ( !(ref_ = PL_new_term_ref()) ||
     !PL_unify_wchars(ref_, PL_ATOM, text.size(), text.data()) )
   throw PlResourceError();

kamahen avatar Aug 03 '22 20:08 kamahen

Yes, the current way to handle text is using PL_get_*chars() and PL_unify_*chars(). The old stuff was from the days atoms where 0-terminated ASCII C strings and the *n* variations when they became char*/length pairs. The new functions can deal with many more scenarios. Best use with CVT_EXCEPTION and re-throw the exception prepared by Prolog. In that case you get the correct exception.

Eventually the wchars versions may possibly go as well and we can use REP_WCHAR instead.

JanWielemaker avatar Aug 04 '22 07:08 JanWielemaker

Does this mean that the various PL_put_*() functions are obsolete/deprecated?

If a PL_get() with CVT_EXCEPTION fails, does this mean that PL_exception(0) should always be called? E.g.:

if ( !PL_get_wchars(t, &len, &s, CVT_ALL|CVT_EXCEPTION) )
{ if ( term_t ex = PL_exception()) )
    PlException(ex).cppThrow();
  return FALSE;
}

kamahen avatar Aug 04 '22 09:08 kamahen

Does this mean that the various PL_put_*() functions are obsolete/deprecated?

The ones dealing with text to create atoms/strings/code lists should be considered deprecated. Not sure we should actually deprecate them, they may have special use cases. Possibly we should add PL_put_chars() with functionality as PL_unify_chars(), but overruling the term_t. That avoids a PL_put_variable() and subsequent unification (and thus trailing).

PL_exception(0) should always be called?

It is surely better to let the Prolog primitives generate the exceptions as they are more precise and in any case virtually any of the primitives can generate a (resource) exception. As is, functions that may fail can return FALSE without or with an exception (e.g. PL_unify() may fail due to failing unification or stacks exhausting).

If I had to do the interface again I would have turned 0 in success, return error codes as negative values and a function to turn these into exceptions ...

JanWielemaker avatar Aug 04 '22 10:08 JanWielemaker

On Thu, 4 Aug 2022 at 03:00, Jan Wielemaker @.***> wrote:

Does this mean that the various PL_put_*() functions are obsolete/deprecated?

The ones dealing with text to create atoms/strings/code lists should be considered deprecated. Not sure we should actually deprecate them, they may have special use cases. Possibly we should add PL_put_chars() with functionality as PL_unify_chars(), but overruling the term_t. That avoids a PL_put_variable() and subsequent unification (and thus trailing).

Shall I mark up foreign.doc and SWI-Prolog.h to reflect this?

I was wondering about the difference between PL_put_() and PL_unify_() and of course, it's the trailing. (It's been many many years since I've done WAM-machine like stuff ... I guess I'll look for my copy of Aït-Kaci's tutorial and refresh myself.

PL_exception(0) should always be called?

It is surely better to let the Prolog primitives generate the exceptions as they are more precise and in any case virtually any of the primitives can generate a (resource) exception. As is, functions that may fail can return FALSE without or with an exception (e.g. PL_unify() may fail due to failing unification or stacks exhausting).

What are the "Prolog primitives"?

If I had to do the interface again I would have turned 0 in success, return error codes as negative values and a function to turn these into exceptions ...

We can at least make a C++ interface that makes things easier -- "throw' definitely simplifies the code.

Back to splitting up SWI-cpp.h into multiple files ... this would lose some edit history - do you care? As things stand, I'd still want to verify that all the methods have implementations, and the only way I know of checking this is by a test file that calls everything, so there's not much advantage in splitting SWI-cpp.h into declarations and implementation. But some C++ toolchains might have trouble with "inline" - have no way of verifying with Microsoft's compiler, for example, although I presume it's OK. I don't know what other compilers are in common use.

  • p

— Reply to this email directly, view it on GitHub https://github.com/SWI-Prolog/swipl-devel/issues/1019#issuecomment-1205034257, or unsubscribe https://github.com/notifications/unsubscribe-auth/AIIGNNKATGU5W5UTZBMXRBDVXOIDNANCNFSM55QGC7XA . You are receiving this because you authored the thread.Message ID: @.***>

kamahen avatar Aug 05 '22 00:08 kamahen

About trail with PL_unify_*() ... this only applies for variables that are older than the current choice point (more-or-less), so PL_new_term_ref; PL_unify_*() wouldn't create an entry on the trail, would it?

kamahen avatar Aug 06 '22 17:08 kamahen

According to Trail() (pl-inline.h), local variables are always trailed. It would be a bit digging to find the rationale for that ...

JanWielemaker avatar Aug 07 '22 08:08 JanWielemaker

I thought that local variables are never trailed; only sufficiently old global variables. But perhaps the meaning of "local variable" is different when inside a foreign function?

There's this comment in the code:

Mark() sets LD->mark_bar, indicating  that   any  assignment  above this
value need not be trailed.

Note that the local stack is always _above_ the global stack.

kamahen avatar Aug 07 '22 14:08 kamahen

They are clearly trailed as it tests for > lBase. Whether that is (still) necessary I don't know. It is not my priority to figure this out. Possibly not because local variables are since some time always references to the global stack to simply last-call optimization.

JanWielemaker avatar Aug 07 '22 15:08 JanWielemaker

The more important question (for me) is knowing which functions in SWI-Prolog.h are deprecated. (Because I only want to use non-deprecated functions in SWI-cpp.h.

Anyway, it seems that (for now, anyway), I have no choice but to use PL_unify_wchars() because there's no PL_put_*() equilvaent

kamahen avatar Aug 07 '22 15:08 kamahen

Just use the PL_unify* functions if there is no suitable put version and make sure to use the text exchange functions with the flags and accepting term_t. That should deal with almost all deprecations. I'll find the others :smile:

JanWielemaker avatar Aug 07 '22 15:08 JanWielemaker

Added PL_put_wchars(), so we can do

PL_put_wchars(t, PL_ATOM, len, string);

See fe70225ba6dbb0408014bc3f4faf9f46c2c1b5e9

JanWielemaker avatar Apr 19 '23 15:04 JanWielemaker