Expression/Definition dependency semantics
Dr. Arne Babenhauserheide
(24 Sep 2023 15:44 UTC)
|
Re: Expression/Definition dependency semantics
Daphne Preston-Kendal
(24 Sep 2023 15:54 UTC)
|
Re: Expression/Definition dependency semantics
Dr. Arne Babenhauserheide
(24 Sep 2023 16:52 UTC)
|
Re: Expression/Definition dependency semantics Amirouche (24 Sep 2023 20:39 UTC)
|
Re: Expression/Definition dependency semantics
Dr. Arne Babenhauserheide
(25 Sep 2023 10:20 UTC)
|
Re: Expression/Definition dependency semantics
Marc Nieper-Wißkirchen
(25 Sep 2023 11:33 UTC)
|
Re: Expression/Definition dependency semantics
Daphne Preston-Kendal
(24 Sep 2023 21:14 UTC)
|
Re: Expression/Definition dependency semantics
Dr. Arne Babenhauserheide
(25 Sep 2023 10:04 UTC)
|
Re: Expression/Definition dependency semantics
Amirouche
(24 Sep 2023 20:12 UTC)
|
> Daphne wrote: > > > On 24 Sep 2023, at 08:49, Dr. Arne Babenhauserheide xxxxxx@web.de wrote: > > > > > (define (using-later-procedure) > > > (define x (y)) > > > (display x)(newline) > > > (define (y) #t) > > > x) > > … > > > > For details, see > > > https://www.gnu.org/software/guile/manual/html_node/Internal-Definitions.html > These were added in Guile incrementally: first only being able to add > expressions between defines and define in let, and later also defines in > begin. > > Their scope was widened following wishes of users, because being able to > log between defines is extremely useful during debugging. > This started with someone saying “we can implement allowing expressions > between defines easily by using {idea}”. Someone did. People tried it > and loved it. Then inner defines interspersed with expression was > expanded further by others. > > Before we had this, many people used intermediate (let …) blocks to be > able to add an expression. After lifting the limitation, almost all of > those became unnecessary. Design issue is not "interleaving definition, and expression" the problem is use-before-definition, that is also known in c as use-before-initialization. > From this experience I think that > > > It is an error for the evaluation of any expression or of the > > right-hand side of any definition in the sequence of definition or > > expressions to require knowledge of the value of a variable whose > > definition is to the right of it. > > > is too restrictive. It is the behavior of Racket, but that does not mean > that it is necessarily the best behavior. > > This keeps ordering rules simple (earlier code is always executed before > code that depends on it), but I think it is slightly too limited. > Therefore I would propose a slight extension: > > "It is an error for the evaluation of any expression to require > knowledge of the value of a variable whose definition is to the right of > the expression." > > There is no need to talk about definitions here, because the change is > only that expressions can be interspersed and only for these requiring > knowledge of variables defined later can be problematic. > > This this adding a line that logs can cause previously working code to > throw an error, but it cannot cause subtle changes. > > > Even more bafflingly, this version of using-later-procedure does not work, but the one you gave does: > > > > (define (using-later-procedure) > > (define x (y)) > > (define _1 (display x)) > > (define _2 (newline)) > > (define y (begin (display "y defined\n") (lambda () #t))) > > x) > > > I reported a simpler version of this to guile-devel this morning: > > (define (using-later-variable) > (define x y) > (display x)(newline) > (define y #t) > x) > > From the answer I got the reason is that display is side-effecting code, > so it forces immediate assignment of the value, which at this point is > still undefined. > > Which I think is not the best possible behavior. > > > I have no idea what Guile is doing that this is possible. > > > I don’t know the details either. What I know is that these possibilities > arevery valuable while programming. That breaks the rule I dub 'the scanning rule': For people used to reading from top-bottom, from left-to-right; It is better to read code from top-bottom, from left to right. The point of the scanning rule is to make the code a bare minimum predictable to limit the cognitive effort required to read the code, if the scanning rule is applied, the user can focus on things that matters. Part of the scanning rule, that is more up to debate: Use of letloop for trivial looping Instead of a lambda, and map, or fold. Even in "declarative" expression of computation, important aspects are described first. OT: The question arises rather often in the definition of modules or libraries, where there is sometime the need to have a constant that may be computed at compile time, and that the user force into a top-level library constant. In that case, I recommend letting the compiler constant folding pick it. Somewhat related, often the order of procedure definitions comes up, in my experience, it is too much work to maintain. NB: I do not think the argument: the user is rushing, it does not want to write code to do X... to be a good rationale. NB: I often do (define i (pk fooo bar qux)) NB: IMO SRFI-245 will offer an easier path to explain Scheme See you around Dr Arne