Open andreasabel opened 3 years ago
Flags are toggled from the "outside". The only thing you can do "inside" is to check that configuration is valid.
For example, one can try to compile on Windows with -f+_regex-posix-clib
.
stack
specifically doesn't let you flip flags on will. They are all fixed in the snapshot resolver definition. That is design issue in how Stackage works, as far as I can tell.
I don't understand what you mean by "occurs positively / negatively".
To point to related ideas:
I proposed sometime in the past for these cases to augment the cabal flag definition syntax to change the default:
field to accept a boolean expression, rather than only a constant primitive bool value: #5328
Different platforms tend to have different preferred default configurations; that feature would help with that aspect
The other aspect of being able to express a Prolog-ish fail/0
more first-level and expressive than build-depends: base<0
was the subject of a different ticket (discussion) I can't find right now; the idea was similar to the false
statement suggested above:
if os(windows)
if !flag(_regex-posix-clib)
fail: "windows doesn't provide regex(3) in its libc; please enable _regex-posix-clib"
or variant of this inspired by Python's assert
(but to be considered under propositional logic semantics):
assert: os(windows) => flag(_regex-posix-clib), "windows doesn't provide regex(3) in its libc; please enable _regex-posix-clib"
(the example above assumes a new logic operator to denote logical implication to keep the example more obvious)
@phadej wrote:
Flags are toggled from the "outside". The only thing you can do "inside" is to check that configuration is valid.
The spec says something else:
If the user does not fix the value of a flag, Cabal will try to find a flag assignment in the following way.
For each flag specified, it will assign its default value, evaluate all conditions with this flag assignment, and check if all dependencies can be satisfied. If this check succeeded, the package will be configured with those flag assignments.
If dependencies were missing, the last flag (as by the order in which the flags were introduced in the package description) is tried with its alternative value and so on. This continues until either an assignment is found where all dependencies can be satisfied, or all possible flag assignments have been tried.
So flags can be forced by constraints. Atm, only indirectly ("negatively"), by producing contraditions from specific flag assignments. But we could as well force them directly ("positively".
I don't understand what you mean by "occurs positively / negatively".
Sorry, this is logic speak.
In N implies P
, N
occurs negatively and P
occurs positively. Negative occurrences are in negations and in conditions of implications. In the case of cabal, negative occurrences are in the conditions of an if
, and positive occurrences are in the "actions" (e.g. build-depends: foo
).
I guess I meant "inside as positively. Consider an example
flag someflag
library
flag: someflag
this is most likely nonsense. We force flag toggling because of some effect that flag will have.
So what Herbert says: having a way to express fail
or assert
directly would be better (and a lot easier to implement to, though still far from trivial, IIRC).
I don't think we need to allow flags (or os(windows)
things) to occur "positively".
EDIT: One could translate
library
flag: someflag
into
library
if !flag(someflag)
fail: "inconsistency"
But this is not exactly the same. I'm worried that flag: someflag
will be misunderstood.
I don't think we need to allow flags (or
os(windows)
things) to occur "positively".
I suppose having os
to occur positively would be confusing, since one may want to think of positive things as "actions" (and you cannot possibly change things like os
and impl
:-D).
But flags and package-names (like e.g. optparse-applicative
) are simply variables whose value is constrained by the contents of the cabal file (like build-depends
) and user settings on the command line and whose value is determined by the constraint solver. I do not see a fundamental difference (at least from the logical side) between flags and package-names (and frankly, not either from the UX side).
One could translate
library flag: someflag
into
library if !flag(someflag) fail: "inconsistency"
So the double-negation of a flag-proposition is allowed, but not the flag-proposition itself...
But this is not exactly the same. I'm worried that
flag: someflag
will be misunderstood.
It is logically equivalent, but with the new fail
you get a specific error message. (This is maybe a general mechanism of giving user-defined errors, but orthogonal to the current issue.)
The current translation is this (or logically equivalent):
library
if !flag(someflag)
build-depends: base<0
which is quite some obfuscation.
If flag: foo
is confusing one could have set-flag: foo
.
if os(windows)
set-flag: _regex-posix-clib
Yes. Maybe. I once again forgot to not participate in Cabal development. Have fun! (unsubscribing)
(EDIT: to clarify, and don't make decisions on Cabal anymore, so feel free to ignore my comments)
If I want to enable a flag based on some conditions, I have to do hackery like (N) [1]:
I'd rather be able to state this positively, e.g. (P):
It seems like (N) isn't understood by
stack
[2].In general, it seems that logic isn't first-class in the cabal language. Some propositions can only occur negatively, it seems (like
flag
,os
,true
,false
). Positive occurrence seems to be reserved tobuild-depends
propositions (and maybe some few more).For a start, why cannot
false
occur positively?, to allow me to write:(That's not my ultimate goal, of course.)
[1] https://github.com/haskell-hvr/regex-posix/commit/13c28e9195a13af2ac68b91f76fc975df1156f97#r47401775 [2] https://github.com/commercialhaskell/stack/issues/5404