# \`term\_string/2\` returns \`end\_of\_file\` with null string at the second arg

**URL:** <https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403>\
**Category:** General\
**Created:** [April 26, 2024, 7:52am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403 "2024-04-26T07:52:37Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [April 26, 2024, 7:52am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/1 "2024-04-26T07:52:37Z")

</div>

I forgot reason why end\_of\_file is returned by ‘term\_string’ for the null string.  
Is this widely accepted in Prolog community ? Certainly, it seems difficult  
to define a term for the string “” other than the end\_of\_file.

```prolog
?- term_string("", R).
R = "\"\"".

```

```prolog
% ?- term_string(A, '').
%@ A = end_of_file.
% ?- term_string(A, "").
%@ A = end_of_file.
% ?- term_string(A, 'a').
%@ A = a.

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 26, 2024, 8:34am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/2 "2024-04-26T08:34:34Z")

</div>

The return of `end_of_file` is the consequence of the parser being started on the string. As no term serializes to an empty string, we could consider raising a domain error instead. Note that this also applies for strings that only contain white space and/or comments.

Any opinions on yes/no raising a domain\_error? (or some other error).

---

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [April 26, 2024, 10:58am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/3 "2024-04-26T10:58:36Z")

</div>

I happened to clear a text area of a browser carelessly, then prolog cgi of mine took it  
as if the text ‘end\_of\_file’ is there. I took some time to find what happened. So, as far as this case of mine, raising domain error might have been useful to make debug time shorter to find the input error.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 26, 2024, 2:22pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/4 "2024-04-26T14:22:12Z")

</div>

Another option might be to throw an unexpected end-of-file `syntax_error` exception. Any objections, i.e., a reason to keep returning `end_of_file`?

---

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [April 26, 2024, 4:47pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/5 "2024-04-26T16:47:37Z")

</div>

> [@jan](#):
>
> Another option might be to throw an unexpected end-of-file `syntax_error` exception.

I already adopted this into some related predicate which calls `term_string/2`  
possibly with the empty string, as a minimal workaround for not going into serious debugging.

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [April 27, 2024, 6:51pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/6 "2024-04-27T18:51:52Z")

</div>

> [@jan](#):
>
> raising a domain\_error? (or some other error)

Why not just simple failure of `term_string(T, "")` because there is no valid term. In the same way that e.g. `between(4, 3, N)` returns failure rather than an exception “3 is not in the domain of 4 or above” 😀

Exceptions seem more awkward. Failure seems perfectly logical, no need for more.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [April 27, 2024, 7:35pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/7 "2024-04-27T19:35:17Z")

</div>

An error can give more information, such as where the syntax error was detected. And an error can be easily converted to failure, using catch/3.

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [April 27, 2024, 7:48pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/8 "2024-04-27T19:48:42Z")

</div>

Yes, but even better is to not have to jump through those hoops in the first place, when they don’t add significant benefit 😉

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [April 27, 2024, 10:41pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/9 "2024-04-27T22:41:41Z")

</div>

> [@peter.ludemann](#):
>
> An error can give more information, such as where the syntax error was detected

That could just be the same predicate with a different _arity_, to add a variable indicating syntax error and where. To be used when the program cares about such details.

I suppose my point boils down to: shouldn’t exceptions be the _last_ choice rather than the first choice, in Prolog?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [April 28, 2024, 3:38am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/10 "2024-04-28T03:38:28Z")

</div>

> [@brebs](#):
>
> shouldn’t exceptions be the _last_ choice rather than the first choice, in Prolog?

I suppose it boils down to whether you think a predicate is something that can either succeed (possibly multiple times) or fail; or is it a predicate that should always succeed (there are a few other less common permutations that I’m ignoring). If the latter, I think that throwing an exception makes sense but if the former, then an exception doesn’t make sense.

If I’m programming in C or Go, I need to check the return code after every call, which clutters the code. If I’m programming in Python, Java, or C++, I can use a try/catch if I care about an error (I probably do care for production code, which is why Go’s style is fine for production code) but otherwise I can assume that execution will stop if something unexpected happens. Things like opening a file (which can fail if the file doesn’t exist) or parsing a Prolog term are somewhere at the boundary between the two situations … for example, it might make sense to have an `open/5` that unifies the 5th argument with `ok` or `error(...)` and the programmer needs to check that (this is arguably a bit less cluttered than using catch/3, and allows writing `open(..., ..., ..., Stream, ok)` to cause failure if there’s an error - on the other hand, it’s probably best to wrap things with setup\_call\_cleanup/3). So, I prefer to throw an error rather than have an extra argument that unifies with the error result.

@ridgeworks will probably disagree with me (there was a long thread about this).

---

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [April 28, 2024, 4:57am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/11 "2024-04-28T04:57:03Z")

</div>

> [@brebs](#):
>
> Why not just simple failure of `term_string(T, "")` because there is no valid term. In the same way that e.g. `between(4, 3, N)` returns failure rather than an exception “3 is not in the domain of 4 or above” 😀
> 
> Exceptions seem more awkward. Failure seems perfectly logical, no need for more.

At this moment, I am inclined to agree with this thought, with an yet another similar  
example `arg/3`, with index out of range call, which simply fails nicely for array  
processing.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [April 28, 2024, 6:37am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/12 "2024-04-28T06:37:46Z")

</div>

> [@Errors considered harmful](https://swi-prolog.discourse.group/t/errors-considered-harmful/3574/1):
>
> Interesting discussion on Picat extensions and cuts and I’d like to add my own personal pet peeve with “standard” Prolog. I don’t think there would be much opposition to the topic title. After all (unhandled) errors rip control away from the programmer and terminate the search for solutions. There might be perfectly valid solutions produced by backtracking but they never get to see the light of day. So one of the objectives of debugging a program, in addition to ensuring that successful executi…

the thread that @peter.ludemann meant, most probably

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 28, 2024, 8:20am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/13 "2024-04-28T08:20:40Z")

</div>

> [@brebs](#):
>
> I suppose my point boils down to: shouldn’t exceptions be the _last_ choice rather than the first choice, in Prolog?

That depends IMO. In this case, term\_string/2 already raises a syntax error if the string is not valid Prolog syntax. That is, for larger terms, pretty useful for debugging. Having an extra argument rather than an exception seems a step back. It would require a lot of if-then-else to check this argument while you can catch exceptions at a higher level.

Not (never) having an exception for term\_string/2 seems highly dubious to me. People tend to write failure driven loops processing a lot of strings. A failure will silently omit the invalid strings. I think omitting these should be a choice that is carefully considered.

The current GIT version raises a `syntax_error(end_of_string)` exception.

---

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [April 28, 2024, 10:31am UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/14 "2024-04-28T10:31:00Z")

</div>

> [@jan](#):
>
> The current GIT version raises a `syntax_error(end_of_string)` exception.

Thanks. As your analysis, syntax error is better than failure for this case because there might be  
possible serious error other than syntax error .

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [April 28, 2024, 1:23pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/15 "2024-04-28T13:23:07Z")

</div>

> [@jan](#):
>
> write failure driven loops processing a lot of strings. A failure will silently omit the invalid strings.

Quiet unexpected failures are probably the biggest debugging problem I have in Prolog. Features such as [SSU](https://www.swi-prolog.org/pldoc/man?section=ssu) and the det/1 directive have helped a lot with that; which is why I prefer errors to failure (this also might be because of my experience with Python, Java, C++).

> [@brebs](#):
>
> Exceptions seem more awkward. Failure seems perfectly logical, no need for more.

An error is just failure with some additional information and a different syntax. If I need to process a failure, I write an “if-then-else” -\>/2 (or add a clause); if I need to process an exception, I use catch/3 or setup\_call\_cleanup/3 (or both). In both cases, the handling can happen far away from where the original problem occurred. Logical purity is nice; but some impure pragmatism can help my non-logical brain write code that works (most of the time).

---

<div class="post-metadata">

**Author:** ![brebs](https://avatars.discourse-cdn.com/v4/letter/b/e9c0ed/32.png) [@brebs](https://swi-prolog.discourse.group/u/brebs)\
**Post date:** [April 28, 2024, 2:31pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/16 "2024-04-28T14:31:39Z")

</div>

To hopefully make both camps content: how about adding a variant which has an additional `options` argument, so we could have:

```prolog
term_string(T, "a(", options([fail_silently]))

```

This makes it explicit that the programmer is taking responsibility for the errors.

The default would be to raise an exception.

This could become a standard way to opt-out of exceptions handling.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [April 28, 2024, 3:47pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/17 "2024-04-28T15:47:54Z")

</div>

Needless to say I have a different perspective; particularly with built-in predicates which often can’t be implemented in Prolog, or are built-in for efficiency reasons. Failure should always be preferred over errors except when continued execution isn’t possible, e.g., resource errors.

My perspective:

> [@peter.ludemann](#):
>
> Quiet unexpected failures are probably the biggest debugging problem I have in Prolog.

Prolog is a logic programming language. Failures should always be expected; they’re built into the fundamental paradigm of the language (while errors are non-logical). Turning unexpected failures (and errors) into expected failures is part of the debugging process, for which a pretty capable debugger is provided.

> [@peter.ludemann](#):
>
> An error is just failure with some additional information and a different syntax.

No, the semantics are very different. Errors abort the current computation while failure causes the search for alternative solutions to continue; Prolog being non-deterministic allows for such a possibility. Now one can be turned into the other if you’re prepared add code (and can live with the added expense).

> [@peter.ludemann](#):
>
> Logical purity is nice; but some impure pragmatism can help my non-logical brain write code that works (most of the time).

And I fear this is a common issue. Prolog _is_ different and I think you get the most out of it if you’re prepared to abandon at least some of the “old ways”. But I’m not about to second guess anybody else’s choices (and this is a philosophical fight I weary of).

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [April 28, 2024, 3:57pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/18 "2024-04-28T15:57:27Z")

</div>

> [@brebs](#):
>
> This makes it explicit that the programmer is taking responsibility for the errors.
> 
> The default would be to raise an exception.
> 
> This could become a standard way to opt-out of exceptions handling.

Unfortunately, I think this just leads to feature creep. Better to have the programmer wrap `term_string` in a predicate which implements their desired semantics for their application.

There was some discussion for the original standard about controlling this with an environment flag (O’Keefe IIRC) but this never made it to the final version. Global flags which modify program semantics are generally not a good idea.

---

<div class="post-metadata">

**Author:** ![kuniaki.mukai](https://avatars.discourse-cdn.com/v4/letter/k/c67d28/32.png) [@kuniaki.mukai](https://swi-prolog.discourse.group/u/kuniaki.mukai)\
**Post date:** [April 28, 2024, 4:24pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/19 "2024-04-28T16:24:15Z")

</div>

> [@brebs](#):
>
> `term_string(T, "a(", options([fail_silently]))`

“fails\_silently” option might be useful for parsing a large text file with prolog terms  
to know how many syntax error terms are there in the file without  
interruptions. ( I am writing this comment tex’s nonstopmode option in mind, which  
is of course useful option, I think.).

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [April 29, 2024, 1:54pm UTC](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403/20 "2024-04-29T13:54:32Z")

</div>

If we had an api for restarting or resuming reading then end\_of\_file makes a lot of sense.

[Next page](https://swi-prolog.discourse.group/t/term-string-2-returns-end-of-file-with-null-string-at-the-second-arg/7403.md?page=2)
