Replies: 6 comments 2 replies
-
I note that the OCaml function Arguably, we do not need |
Beta Was this translation helpful? Give feedback.
-
I can try to answer some of your questions (there are many!) about the current state of Gospel.
This is exactly what we do at the moment. You can indeed shadow Gospel's stdlib by redefining symbols with the same name, but this is a very natural behaviour for OCaml developers, so I do not quite understand why this is an issue?
It refers to the logical definition. An
That is already what we do. There is an abstract
OCaml functions are not represented as logical functions unless their contract contains a
We already have support for a
Arrays and sequences are now two distinct types in the stdlib, although there is a coercion from arrays to sequences. It is indeed possible to write |
Beta Was this translation helpful? Give feedback.
-
Thanks Clément for your replies! I think it is fine to have a single namespace for OCaml names and Gospel names, with shadowing. I wasn't sure that this was the rule. I also wasn't aware that The fact that a Gospel symbol can be shadowed by a local definition in the OCaml program is fine in theory (this behavior is easy to understand and well-defined) but I think it may lead to undesirable shadowing problems in practice. E.g., assume I have written I suppose that a similar rule exists at the level of modules. So the OCaml module |
Beta Was this translation helpful? Give feedback.
-
I do see a need to distinguish in the logic the type
In the first view, a logical function such as As far as I understand, Gospel and Cameleer (@mariojppereira) currently use the first view, where an array is reflected at the logical level by its content, and there is no way at the logical level to talk or reason about the address of an array. This seems sound (even though OCaml arrays are mutable) because some aliasing restrictions are imposed (by Cameleer?). But, in this approach, some OCaml types cannot be reflected in the logic at all: for instance, the OCaml type CFML (@charguer) uses the second view, where an array is reflected in the logic as a memory location, and a separate "points-to" predicate is used to connect the array with its content. This second view is heavier but seems more general and necessary in order to reason about aliasing and ownership. As a middle ground, it would be possible to let the OCaml type-checker distinguish between two (distinct, incompatible) types of mutable arrays and immutable arrays. An immutable array could be reflected in the logic directly as a logical array (a sequence of elements), whereas a mutable array would more likely have to be reflected in the logic as an address. |
Beta Was this translation helpful? Give feedback.
-
Regarding |
Beta Was this translation helpful? Give feedback.
-
Aliasing, ownership, and logical reflection of mutable objectsThis post is intended to summarize my current thoughts on the treatment of mutable objects: how are these objects described at the logical level, in the specification of a function? MotivationIn Gospel, every OCaml value is automatically and implicitly reflected, or lifted, to the logical level: whenever a variable It is crucial to clearly define this connection between OCaml values and types and Gospel values and types. Mutable objects (references; records with mutable fields; arrays) are problematic because there is a tension between two conflicting desires: we sometimes wish to refer to their address, and sometimes to their content. If This question arises only when both mutable state and aliasing are present. In the absence of mutable state, there would be no need to ever mention the address of an object; one would reason always in terms of its content. In the absence of aliasing (that is, roughly, if two distinct OCaml variables are never allowed to denote the same mutable object), the same is true: the address of a mutable object is irrelevant, and one can reason always in terms of its content (even though this content evolves through time). Gospel as it stands today (February 2022) allows mutability but disallows aliasing: the logical reflection of a mutable object is always its content, never its address. As a result, there is no way of describing data structures that involve aliasing (multiple pointers to a single mutable object), such as a list of not-necessarily-distinct references. To remedy this lack of expressive power, it seems that we must introduce a way of disambiguating whether we wish to speak about the address of a mutable object or about its content. Furthermore, in order to give a sound specification to an operation that updates a mutable object, describing the content of a mutable object should be permitted only when this object is uniquely owned. Thus, for example, if Goals and ConsiderationsHere is a list of goals, or considerations to keep in mind.
Technical Remarks
|
Beta Was this translation helpful? Give feedback.
-
I believe that the Gospel documentation does not clearly explain (and I do not clearly understand) what it means to refer to an OCaml value inside a Gospel formula.
Two questions must be distinguished: first, what names are in scope in a Gospel formula? second, what (logical) type do they have, and what (logical) objects do they denote?
Regarding the first question, it is tempting to state that both the names defined at the OCaml level and the names defined at the logical level are in scope. So, e.g., a formula can refer to
length x
, where the functionlength
has been defined at the logical level andx
is (say) a local variable in the OCaml code. I like this approach, but one must be aware that it quickly runs into collisions. For instance, the OCaml primitive operation+
and the mathematical addition+
have the same name. This particular example may seem tolerable, because (as noted by Mario) most of the time, when we write+
in a formula, we mean mathematical addition. But this means that we must arrange for the mathematical operation+
to shadow the (logical reflection of) the OCaml operation+
. This convention is somewhat brittle, and breaks if the programmer locally redefines+
in the OCaml code; then the mathematical+
would become shadowed and would no longer be accessible. More generally, I believe that we have a huge collision problem because the Gospel logical library contains many objects that have the same names as functions in the OCaml standard library: e.g.,Array.length
denotes both an OCaml function in the OCaml standard library and a logical function in the Gospel library; etc. This does not make sense: when one writesArray.length
in a formula, what is meant? Is it (the logical reflection of) the OCaml functionArray.length
, or the logical functionArray.length
defined in the Gospel library?Regarding the second question, it is tempting at first to think that one can refer to an OCaml variable
x
either inside the OCaml code or inside a Gospel formula, and thatx
denotes an object of "the same type", in fact "the same object" in both cases. E.g., ifx
has typebool
in OCaml, thenx
has typebool
when mentioned in a Gospel formula, and all is well. But this works only for a subset of types that exist both at the OCaml level and at the logical level, with the same meaning. At abstract types, we must make sure that an OCaml value of abstract type is reflected in the logic as a logical value of abstract type. For example,int
should be reflected as a logical value of abstract typeint
, and we should reason separately (say, via a functionview : int -> integer
and a predicateisInt : integer -> Prop
) about the connection betweenint
andinteger
.fun
. (This is what CFML does.) We should reason separately about the fact that an OCaml function "implements" a certain logical function (say, via nested Hoare triples).isPure(f)
, in the logic, to assert that a function is pure. Thus, for instance, amap
function could require its argumentf
to be a pure function, if desired. WhenisPure(f)
holds, wheref
has typet -> u
in OCaml, it would be desirable to viewf
also as an object of typet -> u
in the logic (instead offun
as in the general case). (Perhaps a syntactic marker would be needed, for disambiguation: we may for instance have to write%f
.) (The predicateisPure
may need to also carry an arity, to deal with functions of several arguments.)The predicateisPure
would not be magic: the definition ofisPure(f)
would be thatf
implements%f
. (The details need to be clarified...)In summary, I think it is absolutely fundamental to clearly define what names are in scope in a logical formula, and with what type. These issues are nontrivial, and I don't think they have been fully spelled out yet in Gospel.
Beta Was this translation helpful? Give feedback.
All reactions