Creating a unique reference

I am working on something that resembles concurrency library with channels. There is a special token that I want to send over a channel that denotes end of transmission/stream. I could send some term with special meaning like eof but then the user can never send that term directly. I could of course wrap everything user sends in something like msg/1 and then I can use eof atom internally without worrying. However I was wondering if there was a way to generate kind of unique reference that can’t be reconstructed by the user. So far I have found recorda(foo, foo, Ref) to create new references that are only term-equal to themselves, but I was wondering if there is a “cleaner” way to construct references?

(I am aware of gensym, but theoretically there is nothing preventing same term getting constructed manually or by chance :slight_smile: )

I think that using database reference is a rather clever solution :slight_smile: Never thought about that. It only works in the same process though. In your case, transmission will imply copying. If that is not the case you can use a variable as unique token, although it requires you to be careful not to bind the token by accident.

The user can still get a copy of the DB token using recorded/3. I guess that is useful. You can even avoid that by erasing the record. The reference remains a valid Prolog data item, although you can’t use it to access the record any longer.

Of course, the clean solution is to wrap your term as msg(Term) :slight_smile: It would be my first choice.

Could you use an attributed variable with a unify hook that always fails (or generates an exception)? At least there would be an immediate effect of accidental unification.

Yes. Good point. I recall I have have done that :slight_smile: Something along these lines (not tested).

not_unifyable:attr_unify_hook(_Att, Value) :-
    throw(error(should_not_bind(Value),_)).

unbindable_var(Var) :-
    set_attr(Var, not_unifyable, true).

Might even get away with just using freeze as in:

unbindable_var(Var) :-
    freeze(Var, throw(error(should_not_bind(Var),_))).
1 Like