# Definitions at run-time

## Ivan Tomac — 2005-03-10 07:10:44

    For some strange reason some of the recent posts to this message board made me dig

    through the archives and re-read some of the old posts as well as go through most of the

    papers on Joy again.

    I've noticed one thing that I haven't seen earlier that just doesn't seem to add up. On the

    "Further Frequently Asked Questions about Joy" page

    (http://www.latrobe.edu.au/philosophy/phimvt/joy/faq1.html) Manfred talks about the

    reasons why having defining words avaliable at run-time is a bad idea. The reason he

    states in the end is one relating to creation of variables that act the same way as they

    would in imperative languages.

    I have one question and one (obvious) observation:

    1) Wouldn't this only be a problem with dynamically scoped languages? If Joy was lexically

    scoped this wouldn't be an issue.

    2) The imperative notion of variables can be simulated with files as well. Furthermore the

    whole concept of binding names to values and functions is analogous to concepts of

    filesystems and databases.

    Ivan

## William Tanksley, Jr — 2005-03-13 17:22:24

    Ivan Tomac <e1_t@...> wrote:

     > For some strange reason some of the recent posts to this message board made

    > me dig through the archives and re-read some of the old posts as well as go

    > through most of the papers on Joy again.

     Hey, I did that too :-). It's almost worth being proven wrong to see

    the traffic on the list pick up :-).

     > (http://www.latrobe.edu.au/philosophy/phimvt/joy/faq1.html) Manfred talks about the

    > reasons why having defining words avaliable at run-time is a bad idea. The

    > reason he states in the end is one relating to creation of variables that act the

    > same way as they would in imperative languages.

     That's not quite what he says -- he says that such definitions would

    not act in a way he considers appropriate to functional languages.

    The reason that functional languages don't allow mutable variables is

    because the variables in lambdas aren't mutable; thus, the languages

    modify what they can do in order to more closely conform to their

    models. Definitions in Joy are similar to variables in lambda

    expressions.

    This is a reasonable choice, but not the only one.

     > I have one question and one (obvious) observation:

    > 1) Wouldn't this only be a problem with dynamically scoped languages? If Joy

    > was lexically scoped this wouldn't be an issue.

     Er... True, but not for the reason you're stating. A lexically scoped

    language cannot possibly have defining words available at runtime, so

    no issue. Lexical scope means that definition availability is

    determined only by the static source text. If defining words were

    available at runtime, we'd have dynamic scoping.

    With that said, there's nothing bad about dynamic scope and allowing

    redefinitions.

     > Ivan

     -Billy

## Ivan Tomac — 2005-03-14 04:34:55

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr"

    <wtanksleyjr@g...> wrote:

     > > (http://www.latrobe.edu.au/philosophy/phimvt/joy/faq1.html)

     Manfred talks about the

     > > reasons why having defining words avaliable at run-time is a bad

     idea. The

     > > reason he states in the end is one relating to creation of

     variables that act the

     > > same way as they would in imperative languages.

    >

    > That's not quite what he says -- he says that such definitions would

    > not act in a way he considers appropriate to functional languages.

    >

    > The reason that functional languages don't allow mutable variables

     is

     > because the variables in lambdas aren't mutable; thus, the languages

    > modify what they can do in order to more closely conform to their

    > models. Definitions in Joy are similar to variables in lambda

    > expressions.

    >

     How is that different from what I've just said? You've simply worded

    it better. Imperative variables = mutable variables.

    What I'm saying is that it is possible for a language to not allow

    mutable variables and at the same time provide defining words that

    execute at run-time.

     > This is a reasonable choice, but not the only one.

    >

    > > I have one question and one (obvious) observation:

    > > 1) Wouldn't this only be a problem with dynamically scoped

     languages? If Joy

     > > was lexically scoped this wouldn't be an issue.

    >

    > Er... True, but not for the reason you're stating. A lexically

     scoped

     > language cannot possibly have defining words available at runtime,

     so

     > no issue. Lexical scope means that definition availability is

    > determined only by the static source text. If defining words were

    > available at runtime, we'd have dynamic scoping.

    >

    > With that said, there's nothing bad about dynamic scope and allowing

    > redefinitions.

    >

     Alright. Consider a lexically scoped concatenative language.

    Imagine entering something like this at the prompt (using Manfred's

    notation from the FAQ):

    [a 3] DEF2

    [b a] DEF2

    [a [a 4] DEF2 a] i a b

    and on stack you end up with 3 3 4 3.

    The re-binding occured at run-time and yet the language is lexically

    scoped.

     > -Billy

     Ivan

## William Tanksley, Jr — 2005-03-14 05:54:47

    Ivan Tomac <e1_t@...> wrote:

     >"William Tanksley, Jr" <wtanksleyjr@g...> wrote:

    > > > Manfred talks about the

    > > > reasons why having defining words avaliable at run-time is a bad

    > idea. The

    > > > reason he states in the end is one relating to creation of

    > > > variables that act the

    > > > same way as they would in imperative languages.

    > > That's not quite what he says -- he says that such definitions would

    > > not act in a way he considers appropriate to functional languages.

    > How is that different from what I've just said? You've simply worded

    > it better. Imperative variables = mutable variables.

     Sorry I was unclear. My intended point was that he didn't say that

    dynamic definitions were a _bad_ idea; rather, he explained why he

    didn't personally choose to do it.

     > What I'm saying is that it is possible for a language to not allow

    > mutable variables and at the same time provide defining words that

    > execute at run-time.

     No, I'd disagree -- for the reasons he listed. Now, I don't have any

    argument with a language providing both or neither; but the fact is

    that if you allow dynamic redefinition you've got mutable variables.

     > > Er... True, but not for the reason you're stating. A lexically

    > > scoped

    > > language cannot possibly have defining words available at runtime,

    > > so

    > > no issue. Lexical scope means that definition availability is

    > > determined only by the static source text. If defining words were

    > > available at runtime, we'd have dynamic scoping.

    > Alright. Consider a lexically scoped concatenative language.

    > Imagine entering something like this at the prompt (using Manfred's

    > notation from the FAQ):

    > [a 3] DEF2

    > [b a] DEF2

    > [a [a 4] DEF2 a] i a b

    > and on stack you end up with 3 3 4 3.

    > The re-binding occured at run-time and yet the language is lexically

    > scoped.

     If the definitions are dynamic (at runtime) the language is dynamicly

    scoped. In your above example, if the scoping were truly lexical, the

    third DEF2 would apply to the entire quotation in which it appeared

    (including the initial appearance of a), since that's its lexical

    context.

     > Ivan

     -Billy

## Ivan Tomac — 2005-03-14 13:43:25

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr" <wtanksleyjr@g...> wrote:

     > > What I'm saying is that it is possible for a language to not allow

    > > mutable variables and at the same time provide defining words that

    > > execute at run-time.

    >

    > No, I'd disagree -- for the reasons he listed. Now, I don't have any

    > argument with a language providing both or neither; but the fact is

    > that if you allow dynamic redefinition you've got mutable variables.

    >

     How? In the examples I provided there are no mutable variables. In the last example 'a'

    gets rebound at run-time.

     > > Alright. Consider a lexically scoped concatenative language.

    > > Imagine entering something like this at the prompt (using Manfred's

    > > notation from the FAQ):

    >

    > > [a 3] DEF2

    > > [b a] DEF2

    > > [a [a 4] DEF2 a] i a b

    >

    > > and on stack you end up with 3 3 4 3.

    > > The re-binding occured at run-time and yet the language is lexically

    > > scoped.

    >

    > If the definitions are dynamic (at runtime) the language is dynamicly

    > scoped. In your above example, if the scoping were truly lexical, the

    > third DEF2 would apply to the entire quotation in which it appeared

    > (including the initial appearance of a), since that's its lexical

    > context.

    >

     I don't think so. I'm not good at wording these things (it seems every time I try I get stuck

    in a pointless argument until after about 10 or so posts I finally manage to explain what I

    meant) so I looked up a definition of dynamic binding (surprisingly, finding a simple yet

    consise definition of it took a bit longer then I thought it would).

    To quote the definition:

    "In a dynamically scoped language an identifier can be referred to, not only in the block

    where it is declared, but also in any function or procedure called from within that block,

    even if the called procedure is declared outside the block."

    That is clearly not the case in my examples as a word defined prior to the definition of 'a'

    would not be able to access it even if it is called within the quotation where 'a' has been

    defined.

    Now to look up a definition for lexical or static scoping:

    "In a lexically scoped language, the scope of an identifier is fixed at compile time to some

    region in the source code containing the identifier's declaration. This means that an

    identifier is only accessible within that region (including procedures declared within it).

    This contrasts with dynamic scope where the scope depends on the nesting of procedure

    and function calls at run time.

    Statically scoped languages differ as to whether the scope is limited to the smallest block

    (including begin/end blocks) containing the identifier's declaration or to whole function

    and procedure bodies, or some larger unit of code). The former is known as static nested

    scope."

    In my examples the region is the environment from the point where the actual word has

    been defined - because DEF2 is available at run-time that means it's possible to quote it

    and hence delay it's execution until the quotation has been executed/interpreted using the

    i combinator. The scope of 'a' does not depend on the nesting of words and quotations at

    run-time.

     >

    > -Billy

     Ivan

## William Tanksley, Jr — 2005-03-14 16:02:14

    Ivan Tomac <e1_t@...> wrote:

     >"William Tanksley, Jr" <wtanksleyjr@g...> wrote:

    > > > What I'm saying is that it is possible for a language to not allow

    > > > mutable variables and at the same time provide defining words that

    > > > execute at run-time.

    > > No, I'd disagree -- for the reasons he listed. Now, I don't have any

    > > argument with a language providing both or neither; but the fact is

    > > that if you allow dynamic redefinition you've got mutable variables.

    > How? In the examples I provided there are no mutable variables. In the last example 'a'

    > gets rebound at run-time.

     And the effect is almost exactly the same as a mutable variable --

    right? The only difference is that already-compiled code will see the

    old value (or will it, I'm not sure how Joy handles redefinition?).

    Functional languages have a reason for not allowing mutable variables:

    they destroy the ability to staticly analyse lambda expressions (the

    formal term is that they destroy "referential transparency"). This

    reason applies in this case.

    Now, as I've said before, I don't believe that this reason is very

    compelling for a concatenative language; but it's nonetheless a

    reason.

     > > > Alright. Consider a lexically scoped concatenative language.

    > > > Imagine entering something like this at the prompt (using Manfred's

    > > > notation from the FAQ):

    > > > [a 3] DEF2

    > > > [b a] DEF2

    > > > [a [a 4] DEF2 a] i a b

    > > > and on stack you end up with 3 3 4 3.

    > > > The re-binding occured at run-time and yet the language is lexically

    > > > scoped.

    > > If the definitions are dynamic (at runtime) the language is dynamicly

    > > scoped. In your above example, if the scoping were truly lexical, the

    > > third DEF2 would apply to the entire quotation in which it appeared

    > > (including the initial appearance of a), since that's its lexical

    > > context.

    > I don't think so. I'm not good at wording these things (it seems every time I try I get

    > stuck

    > in a pointless argument until after about 10 or so posts I finally manage to explain what I

    > meant) so I looked up a definition of dynamic binding (surprisingly, finding a simple yet

    > consise definition of it took a bit longer then I thought it would).

    > To quote the definition:

     Interesting definition. I can use it.

     > "In a dynamically scoped language an identifier can be referred to, not only in the block

    > where it is declared, but also in any function or procedure called from within that block,

    > even if the called procedure is declared outside the block."

    > That is clearly not the case in my examples as a word defined prior to the definition of 'a'

    > would not be able to access it even if it is called within the quotation where 'a' has been

    > defined.

     Why do you assume that a word defined prior to the definition of 'a'

    wouldn't be able to access it? How could you possibly enforce that? If

    the definition doesn't happen until runtime, how does your parser know

    what variables have and haven't been defined? It really can't -- an

    unrecognised word has to be assumed to be a variable that's been

    defined earlier in the program's execution, since the parser can have

    no knowledge of what the programmer could dynamicly define.

    What I'm saying is that if your variable definitions are dynamic, your

    scoping also must be dynamic.

     > In my examples the region is the environment from the point where the actual word has

    > been defined - because DEF2 is available at run-time that means it's possible to quote it

    > and hence delay it's execution until the quotation has been executed/interpreted

    > using the i combinator. The scope of 'a' does not depend on the nesting of words

    > and quotations at run-time.

     I don't understand the last sentance. It seems to contradict the rest

    of what you've said.

     > Ivan

     -Billy

## Ivan Tomac — 2005-03-15 08:24:28

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr"

    <wtanksleyjr@g...> wrote:

     > > How? In the examples I provided there are no mutable variables. In

     the last example 'a'

     > > gets rebound at run-time.

    >

    > And the effect is almost exactly the same as a mutable variable --

    > right? The only difference is that already-compiled code will see

     the

     > old value (or will it, I'm not sure how Joy handles redefinition?).

     No it isn't almost exactly the same as a mutable variable. A variable

    is either mutable or it isn't mutable. In this case it isn't mutable -

    you can't change the state, you can however bind a symbol to a new

    value. In lambda terms it's a lot like let expressions.

    The code that has already been compiled will see the old value and

    that is the whole point - you can't change it's state, you can't make

    it see new bindings.

    How Joy handles redefinition is completely irrelevant. The whole point

    of all this is that Joy is trying to separate defining words from all

    other words even though it isn't necessary for what it's trying to

    achieve.

     > Functional languages have a reason for not allowing mutable

     variables:

     > they destroy the ability to staticly analyse lambda expressions (the

    > formal term is that they destroy "referential transparency"). This

    > reason applies in this case.

    >

     I agree. However these are not mutable variables.

     > > "In a dynamically scoped language an identifier can be referred

     to, not only in the block

     > > where it is declared, but also in any function or procedure called

     from within that block,

     > > even if the called procedure is declared outside the block."

    > > That is clearly not the case in my examples as a word defined

     prior to the definition of 'a'

     > > would not be able to access it even if it is called within the

     quotation where 'a' has been

     > > defined.

    >

    > Why do you assume that a word defined prior to the definition of 'a'

    > wouldn't be able to access it? How could you possibly enforce that?

     If

     > the definition doesn't happen until runtime, how does your parser

     know

     > what variables have and haven't been defined? It really can't -- an

     A word defined prior to the definition of 'a' would not have 'a' in

    it's environment therefore it would not be able to access it.

    Defining words are the only words that modify the envionment and

    considering in this case they're no different from other words with

    side-effects (such as IO functions - in fact defining new words is

    really just a form of IO) they can only be executed at run-time.

    Therefore the environment can only be modified at run-time.

    The next quotation that gets entered after the environment has been

    modified will use the new modified environment just like the next

    function that reads from a file after the file has been modified will

    read the updated file.

     > unrecognised word has to be assumed to be a variable that's been

    > defined earlier in the program's execution, since the parser can

     have

    An unrecognized word can be handled in two ways - I've only really

    thought about one but I can't see why the other way wouldn't work. The

    first way, and the one I prefer, is for every undefined binding to be

    just that - undefined. If an undefined word is executed you get an

    error (much in the same way you'd get an error if you tried to divide

    a number by zero). It's an illegal operation.

    The second way is even simpler - reject all undefined bindings at

    compile time.

     > no knowledge of what the programmer could dynamicly define.

    >

    > What I'm saying is that if your variable definitions are dynamic,

     your

     > scoping also must be dynamic.

    >

     Parsing happens at compile time while words are defined at run time -

    the parser has all the information it needs. There are no dynamic

    definitions. All bindings happen at run-time but are static, the

    language is lexically scoped.

     > > In my examples the region is the environment from the point where

     the actual word has

     > > been defined - because DEF2 is available at run-time that means

     it's possible to quote it

     > > and hence delay it's execution until the quotation has been

     executed/interpreted

     > > using the i combinator. The scope of 'a' does not depend on the

     nesting of words

     > > and quotations at run-time.

    >

    > I don't understand the last sentance. It seems to contradict the

     rest

     > of what you've said.

    >

     In a dynamically scoped language, the scope depends on the nesting of

    function calls at run-time. In a statically scoped language it doesn't

    nor does it in my examples.

    The scope extends from the point where a variable has been bound to a

    value (at run-time) to the point where it gets rebound to a new value

    (again at run-time).

    You can have as many levels of nesting as you like, it will not affect

    the scope.

     > -Billy

     Ivan

## William Tanksley, Jr — 2005-03-15 16:33:33

    On Tue, 15 Mar 2005 08:24:28 -0000, Ivan Tomac <e1_t@...> wrote:

     >"William Tanksley, Jr" <wtanksleyjr@g...> wrote:

    >>>How? In the examples I provided there are no mutable variables. In

    >>>the last example 'a' gets rebound at run-time.

    >>And the effect is almost exactly the same as a mutable variable --

    >>right? The only difference is that already-compiled code will see

    >>the old value (or will it, I'm not sure how Joy handles redefinition?).

    > No it isn't almost exactly the same as a mutable variable. A variable

    > is either mutable or it isn't mutable. In this case it isn't mutable -

    > you can't change the state, you can however bind a symbol to a new

    > value. In lambda terms it's a lot like let expressions.

     If it were like let expressions, it would be syntactic, and thus

    determined at compile-time, and thus lexical. But it's not like let

    expressions, because it's none of those. I'll look more at this below.

    I do agree that it's not neccesarily exactly the same as a mutable

    variable -- although for some languages it would be. (For example,

    changing a definition in Lisp or Scheme is required to change the

    behavior of all existing words -- for them, runtime definitions would

    be precisely the same as mutable variables. Forth doesn't work this

    way, so runtime definitions in Forth wouldn't be EXACTLY like mutable

    variables.)

    But you'll notice that I didn't claim an exact analogy -- I said that

    they'd be ALMOST the same. The critical question is whether the

    differences are important to you. I'd argue based on what you've been

    claiming that the differences are irrelevant.

     > The code that has already been compiled will see the old value and

    > that is the whole point - you can't change it's state, you can't make

    > it see new bindings.

     This is true for some languages, not true for others. It's a different

    set of questions as to how and whether a language allows redefinition.

     > How Joy handles redefinition is completely irrelevant. The whole point

    > of all this is that Joy is trying to separate defining words from all

    > other words even though it isn't necessary for what it's trying to

    > achieve.

     I agree that Manfred's choice was arbitrary -- he could have chosen

    something else, and in fact I would have recommended something else.

    But his choice was not unreasonable. Joy is not merely "separating"

    defining words; it's deliberately not providing any defining words.

    The reason is that Joy is supposed to be an exploration of a new idea

    in programming languages; Manfred wanted to reduce that idea as far as

    possible to its pure principles.

     > > Functional languages have a reason for not allowing mutable

    > > variables:

    > > they destroy the ability to staticly analyse lambda expressions (the

    > > formal term is that they destroy "referential transparency"). This

    > > reason applies in this case.

    > I agree. However these are not mutable variables.

     Even supposing that they're not (and the distinction is purely

    artificial, as I'll show below), once again, the *reason* behind the

    choice is the same. Whether the cause is runtime-mutable variables or

    a runtime-mutable main dictionary, the effect is the same: a loss of

    referential transparency.

     >>>"In a dynamically scoped language an identifier can be referred

    >>>to, not only in the block where it is declared, but also in any

    >>>function or procedure called from within that block, even if the

    >>>called procedure is declared outside the block."

    >>>That is clearly not the case in my examples as a word defined

    >>>prior to the definition of 'a' would not be able to access it even

    >>>if it is called within the quotation where 'a' has been defined.

    >>Why do you assume that a word defined prior to the definition of 'a'

    >>wouldn't be able to access it? How could you possibly enforce that?

    >>If the definition doesn't happen until runtime, how does your parser

    >>know what variables have and haven't been defined?

    > A word defined prior to the definition of 'a' would not have 'a' in

    > it's environment therefore it would not be able to access it.

     Here's the critical point, where I prove that your idea of runtime

    redefinitions produces the *exact* same results as mutable variables.

     > Defining words are the only words that modify the envionment and

    > considering in this case they're no different from other words with

    > side-effects (such as IO functions - in fact defining new words is

    > really just a form of IO) they can only be executed at run-time.

    > Therefore the environment can only be modified at run-time.

    > The next quotation that gets entered after the environment has been

    > modified will use the new modified environment just like the next

    > function that reads from a file after the file has been modified will

    > read the updated file.

     What if a quotation gets executed twice, once before a redefinition

    and once after it? Won't the quotation produce different results, in

    spite of containing entirely identical tokens? What if the quotation

    itself contains a definition -- won't the result be a redefinition?

    Isn't this precisely the behavior you'd expect from a mutable

    variable?

    But it gets worse.

     >>unrecognised word has to be assumed to be a variable that's been

    >>defined earlier in the program's execution, since the parser can

    >>have

    > An unrecognized word can be handled in two ways - I've only really

    > thought about one but I can't see why the other way wouldn't work. The

    > first way, and the one I prefer, is for every undefined binding to be

    > just that - undefined. If an undefined word is executed you get an

    > error (much in the same way you'd get an error if you tried to divide

    > a number by zero). It's an illegal operation.

     This is standard for languages that allow dynamic redefinition. In

    fact, it's required, because the compiler-parser (the thing that runs

    at compile-time) has a very hard time determining what words are

    defined and what aren't. In general, it's an impossible task, unless

    you put certain restrictions in place, but I don't see you proposing

    any of those.

    But in order to allow this behavior for unrecognised words, you have

    to allow the exact same behavior for *recognised* words as well. Even

    if the compile-time parser somehow "knows" the definition of a word,

    as you claim, it still cannot be allowed to foist its opinion of what

    the word means on the runtime. The runtime is the true authority; it

    can redefine all of the words, and the new meanings must take effect.

    Why? Because the compile-time functions actually have *no* knowledge

    of definitions, because as you said above, "Therefore the environment

    can only be modified at run-time." If the environment is entirely

    controlled by the runtime, the static compiler cannot and must not

    pretend to have any knowledge of it.

     > The second way is even simpler - reject all undefined bindings at

    > compile time.

     This requires that the compile-time environment have knowledge of

    definitions, which in turn requires that definitions be static, which

    in turn requires that they not be dynamic, and hence that they not be

    runtime.

    Well, to be fair, there's nothing wrong with allowing runtime

    definitions -- but you'd have to include a complete runtime compiler

    as well. This is what Forth does.

     >>What I'm saying is that if your variable definitions are dynamic,

    >>your scoping also must be dynamic.

    > Parsing happens at compile time while words are defined at run time -

    > the parser has all the information it needs. There are no dynamic

    > definitions. All bindings happen at run-time but are static, the

    > language is lexically scoped.

     Do you not see the contradiction within the statement "bindings happen

    at run-time but are static"? "Is static" is the denial of "happens at

    runtime". This is what OO languages talk about when they discuss

    "dynamic binding". It means bindings that can change at runtime.

    Static bindings are bindings that are set at compile-time.

     >>>In my examples the region is the environment from the point where

    >>>the actual word has

    >>>been defined - because DEF2 is available at run-time that means

    >>>it's possible to quote it

    >>>and hence delay it's execution until the quotation has been

    >>>executed/interpreted

    >>>using the i combinator. The scope of 'a' does not depend on the

    >>>nesting of words and quotations at run-time.

    >>I don't understand the last sentance. It seems to contradict the

    >>rest of what you've said.

    > In a dynamically scoped language, the scope depends on the nesting of

    > function calls at run-time. In a statically scoped language it doesn't

    > nor does it in my examples.

     But it does. In your examples, a word will only be defined after the

    word containing its definition is executed. In a staticly scoped

    language, a word is defined everywhere within its lexical scope; in

    your examples, words are only defined after their runtime definitions

    are executed.

     > The scope extends from the point where a variable has been bound to a

    > value (at run-time) to the point where it gets rebound to a new value

    > (again at run-time).

    > You can have as many levels of nesting as you like, it will not affect

    > the scope.

     EXACTLY. Levels of nesting do not affect the scope; only patterns of

    execution affect it. The scoping is (in a sense) chronological; it

    starts when the definer is executed, and ends when an undefiner is

    executed. It's NOT lexical. In a lexical definition, the scope ranges

    over a specific area of the text, and does not vary in any way with

    any runtime decisions.

     > Ivan

     -Billy

## John Cowan — 2005-03-15 19:09:44

    William Tanksley, Jr scripsit:

     > What if a quotation gets executed twice, once before a redefinition

    > and once after it? Won't the quotation produce different results, in

    > spite of containing entirely identical tokens? What if the quotation

    > itself contains a definition -- won't the result be a redefinition?

    > Isn't this precisely the behavior you'd expect from a mutable

    > variable?

     I'm not surprised you're surprised at this notion, but ML-ish languages

    really do behave this way.  If A makes use of B, then redefining B does

    not in any way affect the behavior of A unless and until it too is

    redefined.

    Conceptually, the environment is an a-list, and new definitions are

    pushed down on it, with each new definition capturing the state of the a-list

    as it was at definition time.  ML does not allow runtime definition, so

    the effective scope of a definition is from the point it appears until the

    end of the enclosing definition, or the end of input if there is no enclosing

    definition.

    --

    Barry gules and argent of seven and six,        John Cowan

    on a canton azure fifty molets of the second.   jcowan@...

            --blazoning the U.S. flag               http://www.ccil.org/~cowan

## William Tanksley, Jr — 2005-03-15 20:10:57

    John Cowan <cowan@...> wrote:

     > William Tanksley, Jr scripsit:

    > > What if a quotation gets executed twice, once before a redefinition

    > > and once after it? Won't the quotation produce different results, in

    > I'm not surprised you're surprised at this notion, but ML-ish languages

    > really do behave this way.  If A makes use of B, then redefining B does

     Why did you expect me to be surprised? Why are you bringing up ML in

    this context? Yes, I know ML, but I don't see what it has to do with

    what I'm saying. ML is both lexically scoped and does not allow

    runtime definitions.

     > Barry gules and argent of seven and six,        John Cowan

     -Billy

## John Cowan — 2005-03-15 20:29:52

    William Tanksley, Jr scripsit:

     > Why did you expect me to be surprised? Why are you bringing up ML in

    > this context? Yes, I know ML, but I don't see what it has to do with

    > what I'm saying. ML is both lexically scoped and does not allow

    > runtime definitions.

     In ML, you can see the scope rules (at top level) as either a statement about

    the static program text or as a statement about the dynamic behavior of the

    repl loop.   Considering the latter case, a defun/define in Lisp changes

    the global environment retroactively, an ML definition does not.

    If ML had run-time definitions, they would effectively appear at the bottom of

    the program, having no effects on any existing code.

    --

    Well, I have news for our current leaders       John Cowan

    and the leaders of tomorrow: the Bill of        jcowan@...

    Rights is not a frivolous luxury, in force      http://www.ccil.org/~cowan

    only during times of peace and prosperity.      http://www.reutershealth.com

    We don't just push it to the side when the going gets tough.  --Molly Ivins

## William Tanksley, Jr — 2005-03-15 21:26:47

    John Cowan <cowan@...> wrote:

     > William Tanksley, Jr scripsit:

    > > Why did you expect me to be surprised? Why are you bringing up ML in

    > > this context? Yes, I know ML, but I don't see what it has to do with

    > > what I'm saying. ML is both lexically scoped and does not allow

    > > runtime definitions.

    > In ML, you can see the scope rules (at top level) as either a statement about

    > the static program text or as a statement about the dynamic behavior of the

    > repl loop.   Considering the latter case, a defun/define in Lisp changes

    > the global environment retroactively, an ML definition does not.

     I see your point. Actually, it's the other way around for me -- I

    expect the ML behavior, while the Lisp behavior surprises me.

     > Well, I have news for our current leaders       John Cowan

     -Billy

## John Cowan — 2005-03-15 21:53:35

    William Tanksley, Jr scripsit:

     > I see your point. Actually, it's the other way around for me -- I

    > expect the ML behavior, while the Lisp behavior surprises me.

     I think the difference arises because an ML user at the repl loop is

    conceptually supplying a source-code document lazily, whereas a

    Lisp user at the repl loop is conceptually whacking on a workspace.

    I'm not an APL user, but I think it exhibits Lisp-style behavior and

    for the same reason.

    --

    There is no real going back.  Though I          John Cowan

    may come to the Shire, it will not seem         jcowan@...

    the same; for I shall not be the same.          http://www.reutershealth.com

    I am wounded with knife, sting, and tooth,      http://www.ccil.org/~cowan

    and a long burden.  Where shall I find rest?           --Frodo

## William Tanksley, Jr — 2005-03-15 23:49:25

    John Cowan <cowan@...> wrote:

     > William Tanksley, Jr scripsit:

    > > I see your point. Actually, it's the other way around for me -- I

    > > expect the ML behavior, while the Lisp behavior surprises me.

    > I think the difference arises because an ML user at the repl loop is

    > conceptually supplying a source-code document lazily, whereas a

    > Lisp user at the repl loop is conceptually whacking on a workspace.

    > I'm not an APL user, but I think it exhibits Lisp-style behavior and

    > for the same reason.

     This is probably true, and makes sense. It's interesting that Lisp

    historically used dynamic scoping; lexical scoping is fairly new to

    it.

    APL is something of a different case -- it makes no attempt to be

    lambda-pure, like Lisp sometimes does. So using dynamic scope is no

    surprise.

    By the way, pop quiz: does anyone know of a language that uses dynamic

    definitions with lexical scope? I know of a few...

     > There is no real going back.  Though I          John Cowan

     -Billy

## Ivan Tomac — 2005-03-16 00:46:32

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr"

    <wtanksleyjr@g...> wrote:

     > > No it isn't almost exactly the same as a mutable variable. A

     variable

     > > is either mutable or it isn't mutable. In this case it isn't

     mutable -

     > > you can't change the state, you can however bind a symbol to a new

    > > value. In lambda terms it's a lot like let expressions.

    >

    > If it were like let expressions, it would be syntactic, and thus

    > determined at compile-time, and thus lexical. But it's not like let

    > expressions, because it's none of those. I'll look more at this

     below.

     >

     You're concentrating on the wrong aspect of the analogy. Let

    expressions bind names to values. You cannot change the state of an

    existing binding - you can however create a new binding with the same

    name.

     > I do agree that it's not neccesarily exactly the same as a mutable

    > variable -- although for some languages it would be. (For example,

    > changing a definition in Lisp or Scheme is required to change the

    > behavior of all existing words -- for them, runtime definitions

     would

     > be precisely the same as mutable variables. Forth doesn't work this

    > way, so runtime definitions in Forth wouldn't be EXACTLY like

     mutable

     > variables.)

    >

     Lisp and Scheme are impure functional languages that allow assignment

    and therefore allow mutable variables.

    The language I'm trying to describe does not have mutable variables.

    Interesting you brought Forth up because a subset of Forth that does

    not offer any words you can use to overwrite the dictionary ('!' and

    'C!' for example, but not ',') does exactly what I'm trying to

    describe:

    : A 3 ;

    : B A ;

    : A 4 ;

    B \ 3 is now on the stack

     > But you'll notice that I didn't claim an exact analogy -- I said

     that

     > they'd be ALMOST the same. The critical question is whether the

    > differences are important to you. I'd argue based on what you've

     been

     > claiming that the differences are irrelevant.

    >

     But they're not even close - you cannot change the value in an

    existing binding. They are more like constants than mutable variables.

     > > The code that has already been compiled will see the old value and

    > > that is the whole point - you can't change it's state, you can't

     make

     > > it see new bindings.

    >

    > This is true for some languages, not true for others. It's a

     different

     > set of questions as to how and whether a language allows

     redefinition.

     >

     For this particular language it's not a different set of questions.

    Bindings are static and can't change and the code itself cannot be

    changed either. There is nothing that can be redefined.

     > > How Joy handles redefinition is completely irrelevant. The whole

     point

     > > of all this is that Joy is trying to separate defining words from

     all

     > > other words even though it isn't necessary for what it's trying to

    > > achieve.

    >

    > I agree that Manfred's choice was arbitrary -- he could have chosen

    > something else, and in fact I would have recommended something else.

    > But his choice was not unreasonable. Joy is not merely "separating"

    > defining words; it's deliberately not providing any defining words.

    > The reason is that Joy is supposed to be an exploration of a new

     idea

     > in programming languages; Manfred wanted to reduce that idea as far

     as

     > possible to its pure principles.

    >

     Yes, it is deliberatly not providing any defining words but I feel

    that it is doing it for the wrong reasons.

    There is no reason that defining words available at run-time must be

    able to create mutable variables.

     > > > Functional languages have a reason for not allowing mutable

    > > > variables:

    > > > they destroy the ability to staticly analyse lambda expressions

     (the

     > > > formal term is that they destroy "referential transparency").

     This

     > > > reason applies in this case.

    >

    > > I agree. However these are not mutable variables.

    >

    > Even supposing that they're not (and the distinction is purely

    > artificial, as I'll show below), once again, the *reason* behind the

    > choice is the same. Whether the cause is runtime-mutable variables

     or

     > a runtime-mutable main dictionary, the effect is the same: a loss of

    > referential transparency.

    >

     But the effect isn't the same! Think of it in terms of continuations -

    the current environment (or dictionary if you like) gets implicitly

    passed to every single word.

    The definitions held by the environment are only accessed during

    compilation while the environment itself is only modified at run-time.

    Whatever you do to the environment has no effect on

    quotations/lists/code that has already been compiled - they still use

    the old environment and there is nothing you can do to make them use

    the new environment.

     > > A word defined prior to the definition of 'a' would not have 'a'

     in

     > > it's environment therefore it would not be able to access it.

    >

    > Here's the critical point, where I prove that your idea of runtime

    > redefinitions produces the *exact* same results as mutable

     variables.

     >

    > > Defining words are the only words that modify the envionment and

    > > considering in this case they're no different from other words

     with

     > > side-effects (such as IO functions - in fact defining new words is

    > > really just a form of IO) they can only be executed at run-time.

    > > Therefore the environment can only be modified at run-time.

    > > The next quotation that gets entered after the environment has

     been

     > > modified will use the new modified environment just like the next

    > > function that reads from a file after the file has been modified

     will

     > > read the updated file.

    >

    > What if a quotation gets executed twice, once before a redefinition

    > and once after it? Won't the quotation produce different results, in

    > spite of containing entirely identical tokens? What if the quotation

    > itself contains a definition -- won't the result be a redefinition?

    > Isn't this precisely the behavior you'd expect from a mutable

    > variable?

    >

     Have a look at the examples again. I deliberatly constructed them in

    such a way to show how such a language would address the issues you

    bring up. For conveniance I'll paste both of them in here:

    [current-item 4] DEF2

    [5] [[current-item [current-item 8] DEF2] times] infra

    The end-result on stack is [4 4 4 4 4], not [4 8 8 8 8]. The

    environment changes with every iteration due to the DEF2 inside the

    loop. However the quotation has already been compiled and cannot be

    changed. Second example:

    [a 3] DEF2

    [b a] DEF2

    [a [a 4] DEF2 a] i a b

    and on stack you end up with 3 3 4 3.

     > >>unrecognised word has to be assumed to be a variable that's been

    > >>defined earlier in the program's execution, since the parser can

    > >>have

    >

    > > An unrecognized word can be handled in two ways - I've only really

    > > thought about one but I can't see why the other way wouldn't

     work. The

     > > first way, and the one I prefer, is for every undefined binding

     to be

     > > just that - undefined. If an undefined word is executed you get an

    > > error (much in the same way you'd get an error if you tried to

     divide

     > > a number by zero). It's an illegal operation.

    >

    > This is standard for languages that allow dynamic redefinition. In

    > fact, it's required, because the compiler-parser (the thing that

     runs

     > at compile-time) has a very hard time determining what words are

    > defined and what aren't. In general, it's an impossible task, unless

    > you put certain restrictions in place, but I don't see you proposing

    > any of those.

    >

     That's because no restrictions are necessary as it's lexically scoped

    and doesn't allow mutable variables.

    There is a reason why I prefer the first way but it's irrelevant to

    this discussion - for the purposes of what I'm trying to describe the

    second way is probably a better way of handling undefined bindings

    although clearly DEF2 wouldn't be possible in such a language and

    would have to be replaced by DEF (I'm again referring to the functions

    Manfred described in "Further Frequently Asked Questions about Joy").

     > But in order to allow this behavior for unrecognised words, you have

    > to allow the exact same behavior for *recognised* words as well.

     Even

     > if the compile-time parser somehow "knows" the definition of a word,

    > as you claim, it still cannot be allowed to foist its opinion of

     what

     > the word means on the runtime. The runtime is the true authority; it

    > can redefine all of the words, and the new meanings must take

     effect.

     > Why? Because the compile-time functions actually have *no* knowledge

    > of definitions, because as you said above, "Therefore the

     environment

     > can only be modified at run-time." If the environment is entirely

    > controlled by the runtime, the static compiler cannot and must not

    > pretend to have any knowledge of it.

    >

     Compile time parser has access to the environment in the same way

    Forth parser has access to the dictionary and again in the same way

    Caml, Scheme, Haskell all have access to the definitions that have

    already been defined.

    Everything has access to the environment - it helps if you think about

    it in terms of a repl loop rather then a separate compile/run cycle.

     > > The second way is even simpler - reject all undefined bindings at

    > > compile time.

    >

    > This requires that the compile-time environment have knowledge of

    > definitions, which in turn requires that definitions be static,

     which

     > in turn requires that they not be dynamic, and hence that they not

     be

     > runtime.

    >

     Read above.

     > Well, to be fair, there's nothing wrong with allowing runtime

    > definitions -- but you'd have to include a complete runtime compiler

    > as well. This is what Forth does.

    >

     That is only necessary for dynamically scoped languages. And as far as

    I know Forth doesn't need to do this either in the absense of EVALUATE

    (there are possibly some special cases considering Forth pretty much

    lets you do anything to it.. I think the statement holds for most

    Forth programs though).

     > >>What I'm saying is that if your variable definitions are dynamic,

    > >>your scoping also must be dynamic.

    >

    > > Parsing happens at compile time while words are defined at run

     time -

     > > the parser has all the information it needs. There are no dynamic

    > > definitions. All bindings happen at run-time but are static, the

    > > language is lexically scoped.

    >

    > Do you not see the contradiction within the statement "bindings

     happen

     > at run-time but are static"? "Is static" is the denial of "happens

     at

     > runtime". This is what OO languages talk about when they discuss

    > "dynamic binding". It means bindings that can change at runtime.

    > Static bindings are bindings that are set at compile-time.

    >

     Bindings can be static and still happen at run-time. Dynamic binding

    would imply that the binding itself can be changed which is not the

    case here. A new binding gets created in the environment but all the

    old bindings, even the ones with the same name are preserved.

     > >>>In my examples the region is the environment from the point where

    > >>>the actual word has

    > >>>been defined - because DEF2 is available at run-time that means

    > >>>it's possible to quote it

    > >>>and hence delay it's execution until the quotation has been

    > >>>executed/interpreted

    > >>>using the i combinator. The scope of 'a' does not depend on the

    > >>>nesting of words and quotations at run-time.

    >

    > >>I don't understand the last sentance. It seems to contradict the

    > >>rest of what you've said.

    >

    > > In a dynamically scoped language, the scope depends on the

     nesting of

     > > function calls at run-time. In a statically scoped language it

     doesn't

     > > nor does it in my examples.

    >

    > But it does. In your examples, a word will only be defined after the

    > word containing its definition is executed. In a staticly scoped

    > language, a word is defined everywhere within its lexical scope; in

    > your examples, words are only defined after their runtime

     definitions

     > are executed.

    >

     But the word IS defined everywhere within its lexical scope! I think

    the problem is that you're still thinking about this as if the word

    gets defined at compile time - as if the lexical scope of a variable

    should begin right after DEF or DEF2 has been compiled.

    When the parser encounters DEF (or DEF2) within another quotation it

    treats it the same way it would treat any other word - it compiles it,

    it doesn't execute it.

    When you execute the quotation, that's when the binding gets created.

    That is the beginning of the scoping region for that binding.

    Think about it this way - a quotation that contains a defining word

    becomes a defining quotation - becomes a defining word itself.

    Any quotations compiled after that particular quotation has been

    executed will use the bindings in the new environment created by that

    quotation.

     > > The scope extends from the point where a variable has been bound

     to a

     > > value (at run-time) to the point where it gets rebound to a new

     value

     > > (again at run-time).

    > > You can have as many levels of nesting as you like, it will not

     affect

     > > the scope.

    >

    > EXACTLY. Levels of nesting do not affect the scope; only patterns of

    > execution affect it. The scoping is (in a sense) chronological; it

    > starts when the definer is executed, and ends when an undefiner is

    > executed. It's NOT lexical. In a lexical definition, the scope

     ranges

     > over a specific area of the text, and does not vary in any way with

    > any runtime decisions.

    >

     Read what I said above.

     > -Billy

     Ivan

## William Tanksley, Jr — 2005-03-18 18:08:56

    Ivan Tomac <e1_t@...> wrote:

     >"William Tanksley, Jr" <wtanksleyjr@g...> wrote:

    >>>No it isn't almost exactly the same as a mutable variable. A

    >>>variable is either mutable or it isn't mutable. In this case it isn't

    >>>mutable - you can't change the state, you can however bind a

    >>>symbol to a new value. In lambda terms it's a lot like let

    >>>expressions.

    >>If it were like let expressions, it would be syntactic, and thus

    >>determined at compile-time, and thus lexical. But it's not like let

    >>expressions, because it's none of those. I'll look more at this

    >>below.

    >You're concentrating on the wrong aspect of the analogy.

     Possible. I've been known to do that.

     >Let

    >expressions bind names to values. You cannot change the state of an

    >existing binding - you can however create a new binding with the same

    >name.

     I do agree, of course, that let expressions allow you to "shadow"

    variables; the smaller-scoped variable obscures the larger-scoped one

    while inside the narrower scope. But this is part of scoping in

    general, not just lexical scoping; the fact that your proposal does

    the same thing doesn't mean that your proposal is also lexical. It

    just means that both are scoping. The critical difference is that

    lexical scoping is controlled by the syntax of the language, not by

    the semantics. Each defined name has a specific point (byte) in the

    source text at which it becomes defined, and a specific point at which

    it becomes undefined. With dynamic definitions, there is (sometimes)

    no fixed point in the source text at which a variable becomes defined;

    rather, there's a step in the execution at which the variable will

    become defined. It's conceivable that the variable might not become

    defined at all, if the definition is executed within an 'if', and a

    later use of the defined name might work because it was appropriately

    guarded by a completely different 'if'.

    This becomes important for us because if names can become defined at

    arbitrary locations within lexical boundaries, then textual

    manipulations that should be legal within lexical boundaries become

    illegal under certain circumstances. This is obviously critical to a

    language that's trying to make theoretical points about formal textual

    manipulation.

    Now, for a language that's not trying to make any such points, dynamic

    definition is absolutely an open option, and I entirely agree with you

    that no language should rule it out.

     >>I do agree that it's not neccesarily exactly the same as a mutable

    >>variable -- although for some languages it would be. (For example,

    >>changing a definition in Lisp or Scheme is required to change the

    >>behavior of all existing words -- for them, runtime definitions

    >>would be precisely the same as mutable variables. Forth doesn't

    >>work this way, so runtime definitions in Forth wouldn't be

    >>EXACTLY like mutable variables.)

    > Lisp and Scheme are impure functional languages that allow assignment

    > and therefore allow mutable variables.

     Yes; and that's why they don't have a problem with allowing dynamic definitions.

     > The language I'm trying to describe does not have mutable variables.

     It sounds like a fine language. I have no problem with it. But it's

    not Joy -- it doesn't meet the goal of being maximally similar to

    classical functional languages, by preserving as much as possible

    referential transparency.

     > Interesting you brought Forth up because a subset of Forth that does

    > not offer any words you can use to overwrite the dictionary ('!' and

    > 'C!' for example, but not ',') does exactly what I'm trying to

    > describe:

     Yup. Forth is one of my favorite languages (although Factor kicks its

    butt in many ways :-); but Forth, even if reworked into a more purely

    concatenative language, isn't suitable for Joy's goals, partly because

    its allowance of dynamic definitions.

    Keep in mind the context here -- we're asking whether Joy's decision

    to use syntax for definitions is justified. We both agree that it's

    not essential to a concatenative language that its definitions be

    static; defining new words doesn't mess up concatenativity. However,

    you have to consider the specific context of Joy, which is intended

    not to be a pure theoretic sibling of Forth, but rather to be the

    first concatenative functional language. As such, he considered

    referential transparency to be very important.

     > > But you'll notice that I didn't claim an exact analogy -- I said

    > > that

    > > they'd be ALMOST the same. The critical question is whether the

    > > differences are important to you. I'd argue based on what you've

    > > been claiming that the differences are irrelevant.

    > But they're not even close - you cannot change the value in an

    > existing binding. They are more like constants than mutable variables.

     From the point of view of textual manipulations -- you know, like the

    rule that you can always join two valid concatenative programs

    together and get another valid concatenative program -- dynamic

    bindings act precisely like variables, because the meaning of the name

    can change based on when the text gets read in. With lexical scoping,

    the only thing that matters is the position of the text within the

    source code.

     > > > The code that has already been compiled will see the old value and

    > > > that is the whole point - you can't change it's state, you can't

    > > > make it see new bindings.

    > > This is true for some languages, not true for others. It's a

    > > different set of questions as to how and whether a language

    > > allows redefinition.

    > For this particular language it's not a different set of questions.

    > Bindings are static and can't change and the code itself cannot be

    > changed either. There is nothing that can be redefined.

     Joy doesn't work this way (IIRC, quotations can contain undefined

    words), and neither does your ideal language (you just said that if a

    word is undefined, it would get compiled anyhow in the hopes that a

    dynamic definition would be able to determine its meaning before it

    had to be run). This is changing the meaning of a word after it's

    compiled; and hence, it's dynamic binding.

     > > I agree that Manfred's choice was arbitrary -- he could have chosen

    > > something else, and in fact I would have recommended something else.

    > > But his choice was not unreasonable. Joy is not merely "separating"

    > > defining words; it's deliberately not providing any defining words.

    > > The reason is that Joy is supposed to be an exploration of a new

    > > idea in programming languages; Manfred wanted to reduce that idea

    > > as far as possible to its pure principles.

    > Yes, it is deliberatly not providing any defining words but I feel

    > that it is doing it for the wrong reasons.

    > There is no reason that defining words available at run-time must be

    > able to create mutable variables.

     There is no way to prevent them from creating almost the same effect

    as mutable variables. Absolutely no way. The only way you can tell the

    effects apart is:

    1. Languages with static bindings will be able to tell by comparing

    the current value to older bindings that used that name.

    2. Languages that provide a way to undefine names will be able to

    undefine the new value, and the value of the name will change back to

    the old value.

    Other than those two very technical points, dynamic definitions create

    something that looks like a mutable variable.

     > > Even supposing that they're not (and the distinction is purely

    > > artificial, as I'll show below), once again, the *reason* behind the

    > > choice is the same. Whether the cause is runtime-mutable variables

    > > or a runtime-mutable main dictionary, the effect is the same: a loss

    > > of referential transparency.

    > But the effect isn't the same!

     I don't see that. It looks the same, and you haven't shown otherwise.

    But even if the effect has MANY more different elements than I've

    managed to point out, you STILL lose referential transparency, just

    like you do with mutable variables.

     > Think of it in terms of continuations -

    > the current environment (or dictionary if you like) gets implicitly

    > passed to every single word.

     Just as with continuations and other extensions to the basic

    stack-passing model of concatenative languages, this extension

    destroys some of the rules that hold about functional languages.

     > The definitions held by the environment are only accessed during

    > compilation while the environment itself is only modified at run-time.

    > Whatever you do to the environment has no effect on

    > quotations/lists/code that has already been compiled - they still use

    > the old environment and there is nothing you can do to make them use

    > the new environment.

     Um... Yes, but...

    When can you define a new word? If you can only define new words at

    runtime, and runtime is always later than compile-time, then how can

    you possibly compile new words? This isn't accurate. Defining new

    words takes place at compile-time; that's the only relevant time for

    it to happen. If you allow dynamic definitions, you ALSO allow

    definitions to be made at runtime. If runtime can never affect

    compile-time, those definitions are useless to the source in which

    they appear.

    You appear to be arguing that runtime definitions can never affect how

    code gets compiled. Of course they can! If they couldn't, the

    definitions would be useless. Now, I suspect you have some distinction

    in your head for when a definition will get used, but nothing you've

    said defines when that time is.

     > > What if a quotation gets executed twice, once before a redefinition

    > > and once after it? Won't the quotation produce different results, in

    > > spite of containing entirely identical tokens? What if the quotation

    > > itself contains a definition -- won't the result be a redefinition?

    > > Isn't this precisely the behavior you'd expect from a mutable

    > > variable?

    > Have a look at the examples again. I deliberatly constructed them in

    > such a way to show how such a language would address the issues you

    > bring up. For conveniance I'll paste both of them in here:

    > [current-item 4] DEF2

    > [5] [[current-item [current-item 8] DEF2] times] infra

    > The end-result on stack is [4 4 4 4 4], not [4 8 8 8 8]. The

    > environment changes with every iteration due to the DEF2 inside the

    > loop. However the quotation has already been compiled and cannot be

    > changed. Second example:

     It seems you're assuming that compilation proceeds one line at a time,

    with all symbols contained in a single line always having a consistent

    meaning, no matter what redefinitions appear within that line. This is

    a very arbitrary rule, and quite dangerous -- it means that code could

    possibly work one way, then you add a word and change the formatting,

    and it works another way. I'm going to draw my examples below assuming

    (and illustrating) this rule, but keep in mind that my objections are

    not limited to it. Any rule you can come up with will result in

    dynamic definition being in some way equivalent to mutable variables.

    (I can see that another possible rule you might be using is that all

    items in a single quotation are compiled at the same time, so no

    definitions made during the execution of the quotation will affect it.

    My examples also work with that assumption, just in case that's the

    rule you were following. I hope for your sake that it wasn't, since

    that rule is antithetical to lexical scoping; in lexical scoping

    definitions only affect stuff _contained_ within the definition's

    lexical body, while by this rule definitions only can affect stuff not

    contained within the lexical body that contains the definition.)

    First a baseline:

    [current-item 4] DEF2

    [5] [[current-item [current-item 8] DEF2] times] infra current-item

    I'd expect [4 4 4 4 4] 4 from this. But by moving the last word only:

    [current-item 4] DEF2

    [5] [[current-item [current-item 8] DEF2] times] infra

    current-item

    I'd expect [4 4 4 4 4] 8, right? Okay, what happens when I do:

    [current-item 4] DEF2

    [0] [[current-item [current-item 8] DEF2] times] infra

    current-item

    Notice that the definition is now being executed zero times? Now what

    happens? I'd expect [] 4. The problem would be even worse if the

    intial definition of current-item were missing, but I'm sure you

    expect that.

    Now what:

    [current-item 4] DEF2

    [5] [[current-item [current-item current-item 1 +] DEF2] times] infra

    current-item

    Interestingly, this produces [4 4 4 4 4] 5, right? Oh, and also; if

    you undefine current-item, you'll find that the old value was 5 as

    well, since there are actually 5 new definitions.

    Suppose you decide that "swap infra" is a useful term for some reason.

    What happens to:

    [current-item 4] DEF2

    [[current-item [current-item current-item 1 +] DEF2] times]

    [current-item] swap infra

    You'd expect this to be identical to the original program, right? But

    it doesn't fit on a single line, so I reformat it:

    [current-item 4] DEF2

    [[current-item [current-item current-item 1 +] DEF2] times]

        [current-item] swap infra

    Problem! This isn't the same as the original anymore.

     > [a 3] DEF2

    > [b a] DEF2

    > [a [a 4] DEF2 a] i a b

    > and on stack you end up with 3 3 4 3.

     These aren't particularly dynamic uses of definition -- surely you

    agree that there's no need to have dynamic definition if you don't

    actually use it with any conditionals or other dynamic structures.

    Now, all of my above examples are assuming your second, disfavored

    rule (I quote it in the next quote), that undefined words get

    immediately rejected by the compiler (as in Forth). If we use your

    first rule (which you prefer), that undefined words get accepted by

    the compiler and their meaning is determined by the meaning at the

    time the word is run, the problem gets more severe. Either your

    compiler is completely dynamicly bound, as Lisp is (in which case your

    entire argument is useless and dynamic definitions are exactly the

    same as mutable variables), or it's dynamicly bound only for word that

    don't have a current definition _for the compiler_, at the time the

    compilation starts. Definitions made within the

    word/line/unit/whatever being compiled don't count for this; they will

    only be seen at runtime.

    This will just be confusing.

     > > > An unrecognized word can be handled in two ways - I've only really

    > > > thought about one but I can't see why the other way wouldn't

    > > > work. The

    > > > first way, and the one I prefer, is for every undefined binding

    > > > to be

    > > > just that - undefined. If an undefined word is executed you get an

    > > > error (much in the same way you'd get an error if you tried to

    > > > divide a number by zero). It's an illegal operation.

    > > This is standard for languages that allow dynamic redefinition. In

    > > fact, it's required, because the compiler-parser (the thing that

    > > runs

    > > at compile-time) has a very hard time determining what words are

    > > defined and what aren't. In general, it's an impossible task, unless

    > > you put certain restrictions in place, but I don't see you proposing

    > > any of those.

    > That's because no restrictions are necessary as it's lexically scoped

    > and doesn't allow mutable variables.

     Non sequitur. Lexical scoping isn't meaningful for your language as

    you've described it (your language is definitely NOT lexically scoped,

    as I've shown above, since new definitons are NOT available within the

    block in which they lexically appear), and mutable variables have

    nothing whatsoever to do with the problem.

    The restrictions that would help would include things like: "dynamic

    definitions can only be used in runtime code, not inside of a

    definition." That one requirement would ease all of the restrictions.

     > > But in order to allow this behavior for unrecognised words, you have

    > > to allow the exact same behavior for *recognised* words as well.

     By the way, I was technically wrong here. You could behave differently

    for recognised and unrecognised words -- but there would be

    consequences. Dynamic binding and static binding behave very

    differently, and you would be making two visually identical words

    behave totally differently. In fact, in a complex application with a

    lot of modules, this difference could make the order of loading the

    modules critical to the running of the application, since it could

    change a word from being staticly defined with one meaning, staticly

    defined with another meaning, and dynamicly defined with the meanings

    switching depending on which module was most recently called.

     > > Well, to be fair, there's nothing wrong with allowing runtime

    > > definitions -- but you'd have to include a complete runtime compiler

    > > as well. This is what Forth does.

    > That is only necessary for dynamically scoped languages.

     This has nothing at all to do with dynamic scoping. Dynamic scoping

    only requires a runtime dictionary, not a compiler.

     > And as far as

    > I know Forth doesn't need to do this either in the absense of EVALUATE

    > (there are possibly some special cases considering Forth pretty much

    > lets you do anything to it.. I think the statement holds for most

    > Forth programs though).

     You're right on all points here. EVALUATE is, however, Forth's

    explicit way to make a binding dynamic.

     > Bindings can be static and still happen at run-time. Dynamic binding

    > would imply that the binding itself can be changed which is not the

    > case here. A new binding gets created in the environment but all the

    > old bindings, even the ones with the same name are preserved.

     I apologise; you're right. My confusion, my fault.

     > > But it does. In your examples, a word will only be defined after the

    > > word containing its definition is executed. In a staticly scoped

    > > language, a word is defined everywhere within its lexical scope; in

    > > your examples, words are only defined after their runtime

    > > definitions are executed.

    > But the word IS defined everywhere within its lexical scope! I think

    > the problem is that you're still thinking about this as if the word

    > gets defined at compile time - as if the lexical scope of a variable

    > should begin right after DEF or DEF2 has been compiled.

     Yes, that's the meaning of the word "lexical scope", as opposed to

    other words like "dynamic scope". Lexical scope means that the word is

    defined over a single, specific area of the source text. Your

    definitions are dynamicly scoped, and some of the suggestions you've

    made in an attempt to repair the problem result in something that I

    could call anti-lexical scoping -- the definitions are dynamicly

    scoped, but they don't become available until after you've _left_ the

    lexical scope in which the definitions are contained.

    It's true that Forth has a similar rule, but Forth also has the rule

    that runtime definitions should take their names from the runtime

    source, to make it clear that the runtime is controlling the

    situation. For example, the Forth word CREATE makes a new named entry

    in the Forth dictionary, but you can't pass the name to it -- it'll

    take the name from the source code available at runtime. It's obvious

    that the resulting word can't be run by the defining word that created

    it, because that word doesn't even know what its name is.

    For example, suppose for some reason I wanted to make a new VARIABLE

    word. I could use the following definition:

    : variable create 1 cells allot ;

    To use it, I type:

    variable x

    0 x !

    (and so on.)

    The name of the variable is provided by the source code at the

    runtime, and the defining word has no need to see it.

    This is something of a digression, but it's also somewhat related,

    since it shows how dynamic definition can be useful.

     > When the parser encounters DEF (or DEF2) within another quotation it

    > treats it the same way it would treat any other word - it compiles it,

    > it doesn't execute it.

    > When you execute the quotation, that's when the binding gets created.

    > That is the beginning of the scoping region for that binding.

     Yes. It's important to notice that a lexically single definition could

    have many scoping regions, and those regions could disappear depending

    on the dynamic specifics of the code executing them. This is why we

    call it dynamic scoping rather than lexical scoping.

     > Ivan

     -Billy

## John Cowan — 2005-03-18 19:37:07

    William Tanksley, Jr scripsit:

     > Yes. It's important to notice that a lexically single definition could

    > have many scoping regions, and those regions could disappear depending

    > on the dynamic specifics of the code executing them. This is why we

    > call it dynamic scoping rather than lexical scoping.

     It's perhaps worth pointing out (as CLtL does) that the term "dynamic scope"

    is a bit of a misnomer.  "Dynamic scope" is really dynamic extent (that is,

    the object bound to the name becomes inaccessible by it at some point

    and indefinite scope (the name can be used anywhere in the code).

    See http://www.supelec.fr/docs/cltl/clm/node43.html for the full details.

    --

    Unless it was by accident that I had            John Cowan

    offended someone, I never apologized.           jcowan@...

            --Quentin Crisp                         http://www.ccil.org/~cowan

## William Tanksley, Jr — 2005-03-18 20:33:47

    John Cowan <cowan@...> wrote:

     > William Tanksley, Jr scripsit:

    > It's perhaps worth pointing out (as CLtL does) that the term "dynamic scope"

    > is a bit of a misnomer.  "Dynamic scope" is really dynamic extent (that is,

    > the object bound to the name becomes inaccessible by it at some point

    > and indefinite scope (the name can be used anywhere in the code).

    > See http://www.supelec.fr/docs/cltl/clm/node43.html for the full details.

     Facinating -- I don't think I've ever heard the distinction made

    before. It doesn't seem to me like a really useful distinction,

    honestly. According to him, "scope" is the lexical area in which the

    definition is available; but if that's the case, the name "lexical

    scope" is a redundancy, and "dynamic scope" is a contradiction in

    terms. Oh, and he defines "extent" as the time over which a definition

    is available; but I don't see how that would ever be useful, since

    there's no such thing as "static extent" in those terms, and dynamic

    extent is uncomputable.

    I'm looking at the definition some more, and I think there's a

    confusing point in it. I think "scope" refers to variables, while

    "extent" refers to data. Some research on this confirms my general

    idea, although it's complicated by the fact than Lisp variables are of

    course a first-class part of the language (and hence they can be

    considered as data).

    In summary, I don't think that page really discusses the issue we're

    discussing; it addresses the specifics of how Lisp works (notice that

    it claims that dynamic scope is a misnomer simply because Lisp doesn't

    actually have dynamic scope, not because dynamic scope is impossible),

    and its specificity makes it less than useful for this discussion.

    But it's not a bad thing to read -- Lisp is a very good language to

    understand better.

     > Unless it was by accident that I had            John Cowan

     -Billy

## John Cowan — 2005-03-18 21:37:47

    William Tanksley, Jr scripsit:

     > Fascinating -- I don't think I've ever heard the distinction made

    > before. It doesn't seem to me like a really useful distinction,

    > honestly. According to him, "scope" is the lexical area in which the

    > definition is available; but if that's the case, the name "lexical

    > scope" is a redundancy,

     Only in the sense that indefinite scope can be understood as "lexical scope

    extending to the whole of the program".

     > and "dynamic scope" is a contradiction in terms.

     Rather, a shorthand expression for "dynamic extent and indefinite scope".

     > Oh, and he defines "extent" as the time over which a definition

    > is available; but I don't see how that would ever be useful, since

    > there's no such thing as "static extent" in those terms, and dynamic

    > extent is uncomputable.

     Extent can be either dynamic or indefinite ("static extent" indeed makes

    no sense), and we can define indefinite extent as "extent from the dynamic

    start of execution to the dynamic end of execution".

     > I'm looking at the definition some more, and I think there's a

    > confusing point in it. I think "scope" refers to variables, while

    > "extent" refers to data.

     Scope does indeed refer to variables.  Extent refers not to data as such,

    but to the *access* to data through a variable.  Dynamic extent means

    that when some event occurs (such as entering a block or a function

    or executing a declaration), the variable is bound to a value, and when

    some other event occurs, the variable ceases to be bound to a value.

    (In some languages a variable may be bound without having a value,

    but there is no point in referencing such a variable until it gets

    a value.)

     > In summary, I don't think that page really discusses the issue we're

    > discussing; it addresses the specifics of how Lisp works (notice that

    > it claims that dynamic scope is a misnomer simply because Lisp doesn't

    > actually have dynamic scope, not because dynamic scope is impossible),

     No, scope (as defined there) cannot be dynamic, because (as you point out)

    scope has to do with the static program text.

    --

    "Well, I'm back."  --Sam        John Cowan <jcowan@...>

## Ivan Tomac — 2005-03-19 02:17:06

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr"

    <wtanksleyjr@g...> wrote:

     > >Let

    > >expressions bind names to values. You cannot change the state of an

    > >existing binding - you can however create a new binding with the

     same

     > >name.

    >

    > I do agree, of course, that let expressions allow you to "shadow"

    > variables; the smaller-scoped variable obscures the larger-scoped

     one

     > while inside the narrower scope. But this is part of scoping in

    > general, not just lexical scoping; the fact that your proposal does

    > the same thing doesn't mean that your proposal is also lexical. It

    > just means that both are scoping. The critical difference is that

    > lexical scoping is controlled by the syntax of the language, not by

    > the semantics. Each defined name has a specific point (byte) in the

    > source text at which it becomes defined, and a specific point at

     which

     > it becomes undefined. With dynamic definitions, there is (sometimes)

    > no fixed point in the source text at which a variable becomes

     defined;

    Although it may not be apparent, the scoping actually IS defined in

    the source text.

    Consider a repl loop in Caml or SML, whichever you prefer. You type in

    an expression, hit enter and the expression is evaluated. You could

    say it happens at run-time.

    Now consider this:

    let f () = print_string "test";;

    You could say that binding of f occured at run-time considering that

    the repl loop evaluates expressions entered by the programmer.

    So then where/when does compilation happen? Between = and ;;. Note

    that without the two parens print_string would have been evaluated

    right away - there would be no compiling - and f would have been bound

    to a unit value - ().

    How is that similar to a concatenative language? Simple - imagine a

    repl loop in a concatenative language that simply evaluates

    expressions. The above example could be written as:

    [f "test" put] DEF2

    or

    "f" ["test" put] DEF

    The binding happens at run-time again - it's the code inside the

    quotation that gets compiled - it's execution is delayed.

    But what about using DEF and DEF2 inside quotations? Again simple:

    [g [f "test" put] DEF2] DEF2

    f does not get defined until g has already been executed.

    Furthermore the following code:

    [g [f "test" put] DEF2] DEF2

    ... code ...

    g

    ... code ...

    ... new definition or quotation that uses f ...

    can be rewritten as:

    [g] DEF2

    ... code ...

    [f "test" put] DEF2

    ... code ...

    ... new definition or quotation that uses f ...

     > rather, there's a step in the execution at which the variable will

    > become defined. It's conceivable that the variable might not become

    > defined at all, if the definition is executed within an 'if', and a

    > later use of the defined name might work because it was

     appropriately

     > guarded by a completely different 'if'.

    >

     Yes but it only affects new quotations entered by the user - no

    existing code is affected. In fact you just described one advantage of

    this approach that I haven't considered before!

    It allows you to do things that in most other languages you have to

    use a preprocessor for - for example compile two different versions of

    a function depending on what OS you're running.

     > This becomes important for us because if names can become defined at

    > arbitrary locations within lexical boundaries, then textual

    > manipulations that should be legal within lexical boundaries become

    > illegal under certain circumstances. This is obviously critical to a

    > language that's trying to make theoretical points about formal

     textual

     > manipulation.

    >

     Ah, but the names do not get bound until run-time! Therefore at

    compile time you're still within the scope of the previous

    environment. Textual manipulations are not affected.

     > Now, for a language that's not trying to make any such points,

     dynamic

     > definition is absolutely an open option, and I entirely agree with

     you

     > that no language should rule it out.

    >

     How is it dynamic? You cannot redefine anything - the language does

    not allow mutable variables.

    Give me an example so I can see what part of what I'm trying to

    explain is unclear.

     > > Lisp and Scheme are impure functional languages that allow

     assignment

     > > and therefore allow mutable variables.

    >

    > Yes; and that's why they don't have a problem with allowing dynamic

     definitions.

     >

     I actually do have a problem with dynamic definitions.

     > > The language I'm trying to describe does not have mutable

     variables.

     >

    > It sounds like a fine language. I have no problem with it. But it's

    > not Joy -- it doesn't meet the goal of being maximally similar to

    > classical functional languages, by preserving as much as possible

    > referential transparency.

    >

     How so? Again give me an example. I thought the examples I've provided

    along with the explainations were sufficient to prove my point but I

    was apparently wrong. Give me an example of how you could define a

    mutable variable in the langauge.

     > > Interesting you brought Forth up because a subset of Forth that

     does

     > > not offer any words you can use to overwrite the dictionary ('!'

     and

     > > 'C!' for example, but not ',') does exactly what I'm trying to

    > > describe:

    >

    > Yup. Forth is one of my favorite languages (although Factor kicks

     its

     > butt in many ways :-); but Forth, even if reworked into a more

     purely

     > concatenative language, isn't suitable for Joy's goals, partly

     because

     > its allowance of dynamic definitions.

    >

     Without words that can be used to overwrite the dictionary (but not

    append to the dictionary!) how can Forth have dynamic definitions?

    Could you give an example?

     > Keep in mind the context here -- we're asking whether Joy's decision

    > to use syntax for definitions is justified. We both agree that it's

    > not essential to a concatenative language that its definitions be

    > static; defining new words doesn't mess up concatenativity. However,

    > you have to consider the specific context of Joy, which is intended

    > not to be a pure theoretic sibling of Forth, but rather to be the

    > first concatenative functional language. As such, he considered

    > referential transparency to be very important.

    >

     I'm just as interested in theory and for the same reason I do not want

    to break referential transparency. And I still fail to see how does

    what I described break referential transparency.

     > > But they're not even close - you cannot change the value in an

    > > existing binding. They are more like constants than mutable

     variables.

     >

    > From the point of view of textual manipulations -- you know, like

     the

     > rule that you can always join two valid concatenative programs

    > together and get another valid concatenative program -- dynamic

    > bindings act precisely like variables, because the meaning of the

     name

     > can change based on when the text gets read in. With lexical

     scoping,

     > the only thing that matters is the position of the text within the

    > source code.

    >

     But that only affects newly entered definitions, not existing ones -

    how can you change the meaning then? A mutable variable is mutable

    because it's contents can change - because the compiler cannot make

    assumptions on whether it's currently bound to 1 or 3. That is not the

    case with static bindings - once 'a' is bound to 3 the compiler knows

    that it can safely replace every occurance of 'a' with 3.

    As compiling and execution are separate and new bindings are defined

    only during execution, after execution the environment is static. You

    cannot add any more bindings at compile-time. Therefore the compiler

    can safely assume that anything in the current environment will not

    change. It can safely replace every occurance of 'a' with 3. I really

    cannot see where you see mutable variables in this.

    Note also that concatenative properties of the language (as I

    understand them anyway) have not been broken - you can still split a

    quotation into two at any point and still get 2 valid programs. You

    can also concatenate any two quotations and again get a valid program.

     > > For this particular language it's not a different set of

     questions.

     > > Bindings are static and can't change and the code itself cannot be

    > > changed either. There is nothing that can be redefined.

    >

    > Joy doesn't work this way (IIRC, quotations can contain undefined

    > words), and neither does your ideal language (you just said that if

     a

     > word is undefined, it would get compiled anyhow in the hopes that a

    > dynamic definition would be able to determine its meaning before it

    > had to be run). This is changing the meaning of a word after it's

    > compiled; and hence, it's dynamic binding.

    >

     I said no such thing.

    I said that words that have not been defined can be handled in two

    ways - I said I personally prefer the way where undefined bindings get

    compiled in anyway (I didn't give a reason for this because it would

    take too long to explain and is completely irrelevant to the

    discussion - it has to do with abstract data structures) - the other

    way which I said is more relevant to the discussion is the one where

    undefined bindings get rejected at compile time.

    I never said anything about dynamic (re)definition of words. In fact I

    keep pointing over and over again that you cannot re-define words at

    run-time - you can only create new bindings - the existing ones remain

    intact. For the purpose of compiling new definitions only the most

    recent binding is used.

     > > Yes, it is deliberatly not providing any defining words but I feel

    > > that it is doing it for the wrong reasons.

    > > There is no reason that defining words available at run-time must

     be

     > > able to create mutable variables.

    >

    > There is no way to prevent them from creating almost the same effect

    > as mutable variables. Absolutely no way. The only way you can tell

     the

     > effects apart is:

    >

    > 1. Languages with static bindings will be able to tell by comparing

    > the current value to older bindings that used that name.

     Which is exactly what happens here. The environment is static at

    compile time - new bindings are only added at run-time.

     > 2. Languages that provide a way to undefine names will be able to

    > undefine the new value, and the value of the name will change back

     to

     > the old value.

    >

    > Other than those two very technical points, dynamic definitions

     create

     > something that looks like a mutable variable.

    >

     I have not once said that the language can undefine anything. Quite

    the opposite. Once created, a binding cannot be removed. It may be

    inaccessible by the programmer due to newly created bindings of the

    same name but it's still accessible by any quotation/definition that

    was compiled at the time before the new binding was created.

     > > But the effect isn't the same!

    >

    > I don't see that. It looks the same, and you haven't shown

     otherwise.

     > But even if the effect has MANY more different elements than I've

    > managed to point out, you STILL lose referential transparency, just

    > like you do with mutable variables.

    >

    > > Think of it in terms of continuations -

    > > the current environment (or dictionary if you like) gets

     implicitly

     > > passed to every single word.

    >

    > Just as with continuations and other extensions to the basic

    > stack-passing model of concatenative languages, this extension

    > destroys some of the rules that hold about functional languages.

    >

     Then once again I'll ask you to give me an example of how such a

    language would create a mutable variable so that I can clear up any

    misconception you may have about what I've said so far.

     > > The definitions held by the environment are only accessed during

    > > compilation while the environment itself is only modified at

     run-time.

     > > Whatever you do to the environment has no effect on

    > > quotations/lists/code that has already been compiled - they still

     use

     > > the old environment and there is nothing you can do to make them

     use

     > > the new environment.

    >

    > Um... Yes, but...

    >

    > When can you define a new word? If you can only define new words at

    > runtime, and runtime is always later than compile-time, then how can

    > you possibly compile new words? This isn't accurate. Defining new

    > words takes place at compile-time; that's the only relevant time for

    > it to happen. If you allow dynamic definitions, you ALSO allow

    > definitions to be made at runtime. If runtime can never affect

    > compile-time, those definitions are useless to the source in which

    > they appear.

    >

     No run-time is not always later then compile-time. In a repl loop you

    can compile a number of definitions, then execute some others, then

    compile more definitions. Which is why I said it helps if you think

    about this in terms of a repl loop rather then a separate compile/run

    cycle.

    And no - defining new words doesn't have anything to do with compile

    time - compiling happens at compile-time. I would argue that binding

    or defining new words happens after compiling in every language. They

    are different even though most languages don't treat them as such. In

    other words a quotation or a code block first has to be compiled

    before it can be bound to a name.

    There are languages that don't have bindings at all and don't let you

    create any for that matter.

     > You appear to be arguing that runtime definitions can never affect

     how

     > code gets compiled. Of course they can! If they couldn't, the

    > definitions would be useless. Now, I suspect you have some

     distinction

     > in your head for when a definition will get used, but nothing you've

    > said defines when that time is.

     No, I'm arguing that run-time definitions cannot change any existing

    bindings, only create new ones. There is a difference.

    Again think let expressions - in a repl loop they get evaluated at

    run-time.

     > > Have a look at the examples again. I deliberatly constructed them

     in

     > > such a way to show how such a language would address the issues

     you

     > > bring up. For conveniance I'll paste both of them in here:

    >

    > > [current-item 4] DEF2

    >

    > > [5] [[current-item [current-item 8] DEF2] times] infra

    >

    > > The end-result on stack is [4 4 4 4 4], not [4 8 8 8 8]. The

    > > environment changes with every iteration due to the DEF2 inside

     the

     > > loop. However the quotation has already been compiled and cannot

     be

     > > changed. Second example:

    >

    > It seems you're assuming that compilation proceeds one line at a

     time,

     > with all symbols contained in a single line always having a

     consistent

     > meaning, no matter what redefinitions appear within that line. This

     is

     > a very arbitrary rule, and quite dangerous -- it means that code

     could

     > possibly work one way, then you add a word and change the

     formatting,

     > and it works another way. I'm going to draw my examples below

     assuming

     > (and illustrating) this rule, but keep in mind that my objections

     are

     > not limited to it. Any rule you can come up with will result in

    > dynamic definition being in some way equivalent to mutable

     variables.

     >

     No - compilation proceeds one top-level quotation at a time. In other

    words it starts when you enter '[' and ends when you enter a matching

    ']'. And all the symbols inside the quotation DO have a consistent

    meaning - that's the whole point of static bindings and that's why I

    keep saying over and over again that at compile time the environment

    is static.

    Redefinitions are not redefinitions until run-time (in fact they're

    not redefinitions at all - they create new bindings, don't change

    existing ones). At compile time DEF and DEF2 are not treated any

    different to any other word - in fact you could say they're just

    symbols with no meaning until run-time and that the quotation they're

    used in has the current environment associated with it and out of that

    envrionment each symbol gets a meaning or a value at run-time!

    As for your statement about reformatting code I'm not sure I

    understand what you mean? Adding a word and changing formatting would

    change the meaning of code in any language.

     > (I can see that another possible rule you might be using is that all

    > items in a single quotation are compiled at the same time, so no

    > definitions made during the execution of the quotation will affect

     it.

     > My examples also work with that assumption, just in case that's the

    > rule you were following. I hope for your sake that it wasn't, since

    > that rule is antithetical to lexical scoping; in lexical scoping

    > definitions only affect stuff _contained_ within the definition's

    > lexical body, while by this rule definitions only can affect stuff

     not

     > contained within the lexical body that contains the definition.)

    >

     That's exactly the rule I'm using and no, it does not conflict with

    the definition of static scoping (it conflicts with the definition of

    static nested scoping however but not static scoping!).

    As I've already mentioned defining a word is not neccessarily the same

    as compiling - defining or binding always happens after compiling in

    both dynamicly and statically scoped languages even though that is not

    apparent in most statically scoped languages. Binding is always

    delayed until the word/function/code block/quotation has already been

    compiled!

    To put it another way - there are only two forms of scoping - dynamic

    and lexical/static - if this isn't dynamic scoping then it can only be

    static/lexical and it isn't dynamic scoping (hopefully I'll eventually

    manage to convice you of that).

     > First a baseline:

    >

    > [current-item 4] DEF2

    > [5] [[current-item [current-item 8] DEF2] times] infra current-item

    >

    > I'd expect [4 4 4 4 4] 4 from this. But by moving the last word

     only:

    Wrong - you'd get [4 4 4 4 4] 8. Compilation happens between '[' and

    ']' at the top level. infra happens at run-time and current-item at

    the end of the line happens after the new binding has already been

    created.

     >

    > [current-item 4] DEF2

    > [5] [[current-item [current-item 8] DEF2] times] infra

    > current-item

    >

    > I'd expect [4 4 4 4 4] 8, right? Okay, what happens when I do:

    >

    > [current-item 4] DEF2

    > [0] [[current-item [current-item 8] DEF2] times] infra

    > current-item

    >

    > Notice that the definition is now being executed zero times? Now

     what

     > happens? I'd expect [] 4.

     Correct. Note that that is exactly the same as this:

    [current-item 4] DEF2

    [0] [[current-item] times] infra current-item

    while the former can be rewritten as:

    [current-item 4] DEF2

    [5] [[current-item] times] infra

    [current-item 8] DEF2

    current-item

     > The problem would be even worse if the

    > intial definition of current-item were missing, but I'm sure you

    > expect that.

    >

    > Now what:

    >

    > [current-item 4] DEF2

    > [5] [[current-item [current-item current-item 1 +] DEF2] times]

     infra

     > current-item

    >

    > Interestingly, this produces [4 4 4 4 4] 5, right?

    >Oh, and also; if

    > you undefine current-item, you'll find that the old value was 5 as

    > well, since there are actually 5 new definitions.

    >

     How can you undefine current-item? Remember that bindings cannot be

    changed once created.

     > Suppose you decide that "swap infra" is a useful term for some

     reason.

     > What happens to:

    >

    > [current-item 4] DEF2

    > [[current-item [current-item current-item 1 +] DEF2] times]

    > [current-item] swap infra

    >

    > You'd expect this to be identical to the original program, right?

     But

     > it doesn't fit on a single line, so I reformat it:

    >

    > [current-item 4] DEF2

    > [[current-item [current-item current-item 1 +] DEF2] times]

    >     [current-item] swap infra

    >

    > Problem! This isn't the same as the original anymore.

    >

     Problem is that you're assuming compilation happens on a line-by-line

    basis. Read above.

     > > [a 3] DEF2

    > > [b a] DEF2

    > > [a [a 4] DEF2 a] i a b

    > > and on stack you end up with 3 3 4 3.

    >

    > These aren't particularly dynamic uses of definition -- surely you

    > agree that there's no need to have dynamic definition if you don't

    > actually use it with any conditionals or other dynamic structures.

    >

     Alright - give me a better example. Whether you use conditionals or

    not it doesn't make a difference - you still can't have mutable

    variables. You can have conditional compilation which is quite

    different and again only affects words defined after the word that

    creates the definition has been executed.

     > Now, all of my above examples are assuming your second, disfavored

    > rule (I quote it in the next quote), that undefined words get

    > immediately rejected by the compiler (as in Forth). If we use your

    > first rule (which you prefer), that undefined words get accepted by

    > the compiler and their meaning is determined by the meaning at the

    > time the word is run, the problem gets more severe. Either your

    > compiler is completely dynamicly bound, as Lisp is (in which case

     your

     > entire argument is useless and dynamic definitions are exactly the

    > same as mutable variables), or it's dynamicly bound only for word

     that

     > don't have a current definition _for the compiler_, at the time the

    > compilation starts. Definitions made within the

    > word/line/unit/whatever being compiled don't count for this; they

     will

     > only be seen at runtime.

    >

    > This will just be confusing.

    >

     No, again you're assuming that just because the symbol is undefined at

    compile time it will be redefined at run-time which is not the case -

    it will remain undefined - anyway I've already addressed this.

     > > That's because no restrictions are necessary as it's lexically

     scoped

     > > and doesn't allow mutable variables.

    >

    > Non sequitur. Lexical scoping isn't meaningful for your language as

    > you've described it (your language is definitely NOT lexically

     scoped,

     > as I've shown above, since new definitons are NOT available within

     the

     > block in which they lexically appear), and mutable variables have

    > nothing whatsoever to do with the problem.

     Read above.

     >

    > The restrictions that would help would include things like: "dynamic

    > definitions can only be used in runtime code, not inside of a

    > definition." That one requirement would ease all of the

     restrictions.

     >

     But there are NO dynamic definitions! Bindings occur at run-time but

    they are completely static! You cannot change them once they have been

    created.

     > > > Well, to be fair, there's nothing wrong with allowing runtime

    > > > definitions -- but you'd have to include a complete runtime

     compiler

     > > > as well. This is what Forth does.

    >

    > > That is only necessary for dynamically scoped languages.

    >

    > This has nothing at all to do with dynamic scoping. Dynamic scoping

    > only requires a runtime dictionary, not a compiler.

    >

     Good point. Still the language in question would not need a run-time

    compiler just like Forth without EVALUATE would not need one.

     > > Bindings can be static and still happen at run-time. Dynamic

     binding

     > > would imply that the binding itself can be changed which is not

     the

     > > case here. A new binding gets created in the environment but all

     the

     > > old bindings, even the ones with the same name are preserved.

    >

    > I apologise; you're right. My confusion, my fault.

    >

     Ah, but you still insist that the language is dynamicly scoped even

    though the bindings are static! Do you not see that all the compiling

    happens at compile time (therefore there is no need for a run-time

    compiler) but all the bindings happen at run-time and are static?

    You cannot change existing bindings and you cannot undefine existing

    bindings. You can only create new ones and they only only affect newly

    defined quotations much like binding a name to an expression in a let

    expression will only affect the code that follows the binding.

    How can the language be dynamically scoped then?

     > > But the word IS defined everywhere within its lexical scope! I

     think

     > > the problem is that you're still thinking about this as if the

     word

     > > gets defined at compile time - as if the lexical scope of a

     variable

     > > should begin right after DEF or DEF2 has been compiled.

    >

    > Yes, that's the meaning of the word "lexical scope", as opposed to

    > other words like "dynamic scope". Lexical scope means that the word

     is

     > defined over a single, specific area of the source text. Your

    > definitions are dynamicly scoped, and some of the suggestions you've

    > made in an attempt to repair the problem result in something that I

    > could call anti-lexical scoping -- the definitions are dynamicly

    > scoped, but they don't become available until after you've _left_

     the

     > lexical scope in which the definitions are contained.

    >

     No, and I will again point out that compiling quotations/code and

    binding a name are not the same. They are two disctinct operations

    even though most languages don't treat them as such. Binding always

    happens after compiling.

     > > When the parser encounters DEF (or DEF2) within another quotation

     it

     > > treats it the same way it would treat any other word - it

     compiles it,

     > > it doesn't execute it.

    > > When you execute the quotation, that's when the binding gets

     created.

     > > That is the beginning of the scoping region for that binding.

    >

    > Yes. It's important to notice that a lexically single definition

     could

     > have many scoping regions, and those regions could disappear

     depending

     > on the dynamic specifics of the code executing them. This is why we

    > call it dynamic scoping rather than lexical scoping.

    >

     No - what you are referring to in this case would be conditional

    compilation. I should state that in this case 'compilation' is a bit

    misleading as it's really just conditional binding of names but the

    traditional term is conditional compilation.

    Dynamic scoping has nothing to do with that - dynamic scoping would

    mean that once I bind 'a' to say 3, and use it within 'b', and then

    later yet use 'b' within 'c' which redefines 'a' to 5, 'b' would use

    'a' as if it has been defined as 5 to start with.

    That's a bit confusing so I'll illustrate that with an example:

    [a 3] DEF2

    [b a] DEF2

    [c [a 5] DEF2 b] DEF2

    c b

    and on stack you end up with 5 3 - that's what would happen in a

    dynamically scoped language (recall that the scope in dynamically

    scoped languages depends on the nesting of function calls at

    run-time).

    In a statically scoped language I'm trying to describe the above code

    would put 3 3 on stack.

     > -Billy

     Ivan

## William Tanksley, Jr — 2005-03-20 05:15:31

    Ivan Tomac <e1_t@...> wrote:

    I'm going to skip a little; I think we're starting to wander. Sorry.

     >"William Tanksley, Jr" <wtanksleyjr@g...> wrote:

    >>Now, for a language that's not trying to make any such points,

    >>dynamic definition is absolutely an open option, and I entirely

    >>agree with you that no language should rule it out.

    > How is it dynamic?

     Dynamic essentially means "happens at runtime". These definitions

    happen at runtime; therefore they are dynamic. (Actually, "dynamic"

    means that the full results can't be known at compile-time, but this

    definitions also applies.)

     > You cannot redefine anything - the language does

    > not allow mutable variables.

     Wait, you're now saying that no name in the source can ever be

    assigned to a value once it's been previously assigned? So once I

    assign 3 to the symbol x, x will only and exclusively have the value

    3, no matter what happens? Nobody else can ever define a variable or

    function using the symbol 'x' ever again?

    If this is true, it's the most restrictive proposal I've ever heard.

     > Give me an example so I can see what part of what I'm trying to

    > explain is unclear.

     I'll clarify the ones I gave. You corrected one of my examples, but

    the rest still stand.

     > was apparently wrong. Give me an example of how you could define a

    > mutable variable in the langauge.

     Just so we understand: I can't, of course, do that. I never claimed

    to. I claimed that the dynamic (runtime) definitions you were

    proposing would interfere with textual manipulations in the same way

    that mutable variables do.

     > Without words that can be used to overwrite the dictionary (but not

    > append to the dictionary!) how can Forth have dynamic definitions?

    > Could you give an example?

     There's a problem with trying that -- Forth has only one linear

    dictionary, so while one word is being compiled, no other compilation

    may take place. So I can't define words while another word is being

    defined. The second problem is that IF and THEN and so on are only

    legal within a definition, so I can't do truly dynamic things with the

    results.

    So the limitations of Forth make this impossible. Your language

    doesn't propose any of those limitations.

     >>>But they're not even close - you cannot change the value in an

    >>>existing binding. They are more like constants than mutable

    >>>variables.

    >>From the point of view of textual manipulations -- you know, like

    >>the rule that you can always join two valid concatenative programs

    >>together and get another valid concatenative program -- dynamic

    >>bindings act precisely like variables, because the meaning of the

    >>name can change based on when the text gets read in. With

    >>lexical scoping,

    >>the only thing that matters is the position of the text within the

    >>source code.

    > But that only affects newly entered definitions, not existing ones -

    > how can you change the meaning then?

     _Textually_, there is no difference between "newly entered" and

    "existing" definitions. If two identical words at the same lexical

    level have different meanings due to dynamic operation of the

    language, the compiler cannot use static analysis.

     > As compiling and execution are separate and new bindings are defined

    > only during execution, after execution the environment is static. You

    > cannot add any more bindings at compile-time. Therefore the compiler

    > can safely assume that anything in the current environment will not

    > change. It can safely replace every occurance of 'a' with 3. I really

    > cannot see where you see mutable variables in this.

     You just described conditional compilation. That's dynamic. I show

    below that loops can also dynamicly change the final values bound to

    variables. The compiler can't pretend the definitions are static; in

    static terms, the compiler can't know which definition will be chosen

    from the IF.

     > Note also that concatenative properties of the language (as I

    > understand them anyway) have not been broken - you can still split a

    > quotation into two at any point and still get 2 valid programs. You

    > can also concatenate any two quotations and again get a valid program.

     Okay, here's an example.

    [x 0] DEF2

    [x [x 1] DEF2]

    [x [x 2] DEF2]

       i swap i

    This should produce (0 1) on the stack, unless I got that wrong. Now,

    by concatenative theory, you should be able to concatenate those two

    quotations together, and get the exact effect of calling them one

    after the other (the swap, of course, just buries the first function's

    result and gets at the address of the second function, so the

    concatenation shouldn't change the final result):

    [x 0] DEF2

    [x [x 1] DEF2 x [x 2] DEF2]

       i

    Now the result is (0 0).

    The result has changed, but nothing's happened that should be

    violating concatenativity, so the result shouldn't change.

     >>Joy doesn't work this way (IIRC, quotations can contain undefined

    >>words), and neither does your ideal language (you just said that if

    >>a

    >>word is undefined, it would get compiled anyhow in the hopes that a

    >>dynamic definition would be able to determine its meaning before it

    >>had to be run). This is changing the meaning of a word after it's

    >>compiled; and hence, it's dynamic binding.

    > I said no such thing.

     Actually, that's what you said, and what you say below.

     > I said that words that have not been defined can be handled in two

    > ways - I said I personally prefer the way where undefined bindings get

    > compiled in anyway

     Okay, and then what happens? "Undefined results"? No, you expect the

    programmer to define the name before the code gets run. You said so

    yourself. And when the code is run, THEN the undefined word will take

    on the current meaning. Who decides what the current meaning is? Not

    the compiler, since the compiler only knows what was defined at the

    time the word was used. Here's an example:

    Assume "print" is defined to print a number. x is not defined.

    [getx x] DEF2

    [x 0] DEF2

    [getx [x getx 1 +] DEF2] 3 times

    (I'm not fluent in Joy -- I probably got "times" wrong. Please assume

    it works the way I wrote it.)

    That code will leave (0 1 2) on the stack and x will be 3, if I read

    your proposal right, because the 'x' in 'getx' has to be rebound when

    it's executed. This has the FULL effect of a mutable variable.

     > the other

    > way which I said is more relevant to the discussion is the one where

    > undefined bindings get rejected at compile time.

     It's easier to reason about languages this way, because all of the

    bindings are static, rather than some being static and some being

    dynamic.

     > I never said anything about dynamic (re)definition of words. In fact I

    > keep pointing over and over again that you cannot re-define words at

    > run-time - you can only create new bindings - the existing ones remain

    > intact. For the purpose of compiling new definitions only the most

    > recent binding is used.

     Irrelevant. The old binding is no longer available. Thus, the symbol

    has been redefined. No, that redefinition is not retroactive (as it

    would be with mutable variables or dynamic binding), but its scope is

    not fixed to any lexical area; its scope depends entirely on how the

    program's execution flows.

     > > 2. Languages that provide a way to undefine names will be able to

    > > undefine the new value, and the value of the name will change back

    > > to  the old value.

    > > Other than those two very technical points, dynamic definitions

    > > create

    > > something that looks like a mutable variable.

    > I have not once said that the language can undefine anything.

     And I didn't say you did. I said that IF a language does provide a way

    to undefine, THEN dynamic definitions can sometimes be told apart from

    variable assignments, because variable assignments cannot be undone,

    but an undefinition is the undoing of a definition.

    But thanks for providing another bit of information about how your

    language works.

     > > You appear to be arguing that runtime definitions can never affect

    > how

    > > code gets compiled. Of course they can! If they couldn't, the

    > > definitions would be useless. Now, I suspect you have some

    > distinction

    > > in your head for when a definition will get used, but nothing you've

    > > said defines when that time is.

    >

    > No, I'm arguing that run-time definitions cannot change any existing

    > bindings, only create new ones. There is a difference.

     I'm not arguing about this. Forget about it. I agree entirely. Please

    don't ever read anything I write in the future as if it were a

    statement contradicting that. I accept that your language doesn't have

    dynamic bindings. I assert that it does have dynamic definitions.

     > No - compilation proceeds one top-level quotation at a time. In other

     Ah, okay. So my second guess was better than my first. Sorry.

     > Redefinitions are not redefinitions until run-time (in fact they're

    > not redefinitions at all - they create new bindings, don't change

    > existing ones).

     Pardon, but they ARE redefinitions. They don't change past uses of the

    bindings, but they DO change the meaning of the text.

     > > that rule is antithetical to lexical scoping; in lexical scoping

    > > definitions only affect stuff _contained_ within the definition's

    > > lexical body, while by this rule definitions only can affect stuff

    > > not

    > > contained within the lexical body that contains the definition.)

    > That's exactly the rule I'm using and no, it does not conflict with

    > the definition of static scoping (it conflicts with the definition of

    > static nested scoping however but not static scoping!).

     According to FOLDOC, the two mean the same thing. Nested scoping just

    means that you can redefine a word and when you undefine it the old

    word will still be there. That's pretty much a requirement of lexical

    scoping; in fact, FOLDOC wasn't able to come up with any examples of

    lexical scoping that weren't also nested lexical.

     > As I've already mentioned defining a word is not neccessarily the same

    > as compiling

     I don't know why you mention it; it appears to have no relation to

    anything I've ever said.

     > To put it another way - there are only two forms of scoping - dynamic

    > and lexical/static - if this isn't dynamic scoping then it can only be

    > static/lexical and it isn't dynamic scoping (hopefully I'll eventually

    > manage to convice you of that).

     I don't see how. It's definitely dynamic, since it happens at runtime.

    See http://foldoc.hld.c64.org/foldoc.cgi?lexical+scope for definitions

    that work for me.

     > > First a baseline:

    > > [current-item 4] DEF2

    > > [5] [[current-item [current-item 8] DEF2] times] infra current-item

    > >

    > > I'd expect [4 4 4 4 4] 4 from this. But by moving the last word

    > only:

    > Wrong - you'd get [4 4 4 4 4] 8. Compilation happens between '[' and

     Whoops, this is the one I got dead wrong. I actually thought I'd

    cleaned it out after I realised that you might be using quotations as

    your compilation boundaries. My bad.

     > > [current-item 4] DEF2

    > > [5] [[current-item [current-item 8] DEF2] times] infra

    > > current-item

    > > I'd expect [4 4 4 4 4] 8, right? Okay, what happens when I do:

     Okay, so this one is the baseline.

     > > [current-item 4] DEF2

    > > [0] [[current-item [current-item 8] DEF2] times] infra

    > > current-item

    > > Notice that the definition is now being executed zero times? Now

    > > what

    > > happens? I'd expect [] 4.

    > Correct.

     But see the problem? The empty list is fine, because it's obviously

    the result of the normal operation of infra and time; but the 4 is

    totally unexpected. The compiler cannot staticly guess that it should

    be 4. Lexically, there was a definition preceding it that should have

    changed it to 8; but dynamicly the program chose not to execute that

    definition.

     > Note that that is exactly the same as this:

    > [current-item 4] DEF2

    > [0] [[current-item] times] infra current-item

     Except for the lack of any definitions, right? Since that's what we're

    discussing, I think that's a pretty painful omission.

     > while the former can be rewritten as:

    > [current-item 4] DEF2

    > [5] [[current-item] times] infra

    > [current-item 8] DEF2

    > current-item

     What if the [5] were dynamicly chosen -- for example, from user input,

    or read in from a file?

     > > The problem would be even worse if the

    > > intial definition of current-item were missing, but I'm sure you

    > > expect that.

    > > Now what:

    > > [current-item 4] DEF2

    > > [5] [[current-item [current-item current-item 1 +] DEF2] times]

    > > infra  current-item

    > > Interestingly, this produces [4 4 4 4 4] 5, right?

    > >Oh, and also; if

    > > you undefine current-item, you'll find that the old value was 5 as

    > > well, since there are actually 5 new definitions.

     You didn't respond to the example, in which the value of current-item

    mutates to 5.

     > > You'd expect this to be identical to the original program, right?

    > > [current-item 4] DEF2

    > > [[current-item [current-item current-item 1 +] DEF2] times]

    > >     [current-item] swap infra

    > > Problem! This isn't the same as the original anymore.

    > Problem is that you're assuming compilation happens on a line-by-line

    > basis. Read above.

     My explanation did assume that. But the program as written does show

    what I wanted to show, that a "safe" manipulation is actually unsafe.

    Exchanging two quotations in the source and then inserting a swap

    should produce the same result; but if the second quotation gets

    executed first and includes a redefinition of a variable in the first

    quotation, the redefinition changes how the second quotation gets

    compiled.

    This could get much much worse, if the two quotations were in

    different libraries.

     > > Now, all of my above examples are assuming your second, disfavored

    > > rule (I quote it in the next quote), that undefined words get

    > > immediately rejected by the compiler (as in Forth). If we use your

    > > first rule (which you prefer), that undefined words get accepted by

    > > the compiler and their meaning is determined by the meaning at the

    > > time the word is run, the problem gets more severe. Either your

    > > compiler is completely dynamicly bound, as Lisp is (in which case

    > your

    > > entire argument is useless and dynamic definitions are exactly the

    > > same as mutable variables), or it's dynamicly bound only for word

    > that

    > > don't have a current definition _for the compiler_, at the time the

    > > compilation starts. Definitions made within the

    > > word/line/unit/whatever being compiled don't count for this; they

    > will

    > > only be seen at runtime.

    > >

    > > This will just be confusing.

    > No, again you're assuming that just because the symbol is undefined at

    > compile time it will be redefined at run-time which is not the case -

    > it will remain undefined - anyway I've already addressed this.

     No, you haven't addressed it; you just claimed I was wrong, and then

    when you tried to explain you stopped the explanation exactly when you

    were about to say what happens when the word is run (which is the

    whole dispute).

    Here's exactly what you claim happens: If the symbol is undefined at

    compile-time, it gets compiled anyhow; in that case, the user/client

    is expected to define the word before running it; if they fail to do

    so, running the word will produce an error. If they do define the

    word, running the word will produce the behavior using the new

    definition.

    I just realised that you left an ambiguity there, so what I thought

    you meant might not be what you actually meant. I thought you meant

    that when the word is run, the system looks through the environment to

    try to find an apprpriate definition for the word that wasn't known at

    compile time. However, you may actually have meant that whenever a

    word is defined for the first time, the system searches all words to

    try to find any formerly unknown uses of that word, and it permanently

    corrects them to match the new definition.

    Is that what you meant?

     > > > That's because no restrictions are necessary as it's lexically

    > scoped

    > > > and doesn't allow mutable variables.

    > > Non sequitur. Lexical scoping isn't meaningful for your language as

    > > you've described it (your language is definitely NOT lexically

    > scoped,

    > > as I've shown above, since new definitons are NOT available within

    > the

    > > block in which they lexically appear), and mutable variables have

    > > nothing whatsoever to do with the problem.

    > Read above.

     This paragraph stands on its own. Your language is prima facia not

    lexically scoped, because new definitions are not confined to their

    lexical context; instead, they follow the dynamic flow of control

    wherever it leads.

     > > The restrictions that would help would include things like: "dynamic

    > > definitions can only be used in runtime code, not inside of a

    > > definition." That one requirement would ease all of the

    > > restrictions.

    > But there are NO dynamic definitions! Bindings occur at run-time but

    > they are completely static! You cannot change them once they have

    > been created.

     You're confusing bindings and definitions. I don't blame you; I did

    too, and I had to be corrected.

     > > > Bindings can be static and still happen at run-time. Dynamic

    > binding

    > > > would imply that the binding itself can be changed which is not

    > the

    > > > case here. A new binding gets created in the environment but all

    > the

    > > > old bindings, even the ones with the same name are preserved.

    > >

    > > I apologise; you're right. My confusion, my fault.

    > Ah, but you still insist that the language is dynamicly scoped even

    > though the bindings are static! Do you not see that all the compiling

    > happens at compile time (therefore there is no need for a run-time

    > compiler) but all the bindings happen at run-time and are static?

     Your bindings are being made at compile-time, not run-time. This is

    why they're called static bindings. But your definitions are being

    made at runtime; this is why your language has an ordinary library

    function, DEF2, which creates a definition at the time it's run. This

    is why your definitions are dynamic.

    Your language is dynamicly scoped because the scope of the variables

    DEF2 creates can only be discovered by discovering the dynamic flow of

    control.

     > You cannot change existing bindings and you cannot undefine existing

    > bindings. You can only create new ones and they only only affect newly

    > defined quotations much like binding a name to an expression in a let

    > expression will only affect the code that follows the binding.

    > How can the language be dynamically scoped then?

     These questions are all questions about binding, not scoping. Thus

    your last question cannot be answered by referencing any of them.

    Oh, by the way, there's no action "undefine an existing binding".

    Bindings can't be defined or undefined. Definitions get defined;

    bindings get bound.

     > > > But the word IS defined everywhere within its lexical scope! I

    > think

    > > > the problem is that you're still thinking about this as if the

    > word

    > > > gets defined at compile time - as if the lexical scope of a

    > variable

    > > > should begin right after DEF or DEF2 has been compiled.

    > >

    > > Yes, that's the meaning of the word "lexical scope", as opposed to

    > > other words like "dynamic scope". Lexical scope means that the word

    > is

    > > defined over a single, specific area of the source text. Your

    > > definitions are dynamicly scoped, and some of the suggestions you've

    > > made in an attempt to repair the problem result in something that I

    > > could call anti-lexical scoping -- the definitions are dynamicly

    > > scoped, but they don't become available until after you've _left_

    > the

    > > lexical scope in which the definitions are contained.

    > No, and I will again point out that compiling quotations/code and

    > binding a name are not the same. They are two disctinct operations

    > even though most languages don't treat them as such. Binding always

    > happens after compiling.

     I'm seriously confused why you're saying this. It seems totally

    irrelevant to what I'm saying. There also seems to be a confusion --

    when you say "binding always happens after compiling" I suspect that

    you mean "definition always occurs after compiling".

     > > Yes. It's important to notice that a lexically single definition

    > could

    > > have many scoping regions, and those regions could disappear

    > depending

    > > on the dynamic specifics of the code executing them. This is why we

    > > call it dynamic scoping rather than lexical scoping.

    > No - what you are referring to in this case would be conditional

    > compilation. I should state that in this case 'compilation' is a bit

    > misleading as it's really just conditional binding of names but the

    > traditional term is conditional compilation.

     Conditional _definition_ of names. AKA dynamic definition.

     > Dynamic scoping has nothing to do with that - dynamic scoping would

    > mean that once I bind 'a' to say 3, and use it within 'b', and then

    > later yet use 'b' within 'c' which redefines 'a' to 5, 'b' would use

    > 'a' as if it has been defined as 5 to start with.

     No, that's dynamic binding (because already-known bindings in

    previously compiled words have to be changed to match new

    definitions).

    Dynamic scoping is different-- in dynamic scoping there's no guarantee

    that you'll be able to access a defined name from any place in the

    source text. Instead, the guarantee is that you'll be able to access

    the defined name chronologically after the definition has been

    executed.

     > That's a bit confusing so I'll illustrate that with an example:

    >

    > [a 3] DEF2

    > [b a] DEF2

    > [c [a 5] DEF2 b] DEF2

    > c b

    >

    > and on stack you end up with 5 3 - that's what would happen in a

    > dynamically scoped language (recall that the scope in dynamically

    > scoped languages depends on the nesting of function calls at

    > run-time).

    > In a statically scoped language I'm trying to describe the above code

    > would put 3 3 on stack.

     That's static binding, definitely.

    If it were static scoping, the DEF2 inside the body of 'c' would only

    change the value of 'a' within a staticly fixed area -- usually the

    quotation within which the definition appears. Joy is a good example

    of this; Joy definitions can be lexically scoped, and when they do so,

    you can use them only within the libra for which they're defined.

     > dynamically scoped language (recall that the scope in dynamically

    > scoped languages depends on the nesting of function calls at

    > run-time).

     That's a true statement, but painfully inadequate as a definition. The

    reason for the unclarity is the statement "the nesting of function

    calls at runtime". It's so unclear to you what this means that when

    you tried to give me an example, your example contained only one

    nested function call (the call from c->b->a), and that nested call

    didn't contain any definitions (so it couldn't possibly be a

    demonstration of this statement).

    The scope of a definition in a dynamicly scoped language begins *when*

    a definition is executed. The scope of a definition in a lexically

    scoped language begins *where* the definition appears in the source.

    See the difference?

     > Ivan

     -Billy

## William Tanksley, Jr — 2005-03-20 05:32:05

    John Cowan <cowan@...> wrote:

     > William Tanksley, Jr scripsit:

    > > Fascinating -- I don't think I've ever heard the distinction made

    > > before. It doesn't seem to me like a really useful distinction,

    > > honestly. According to him, "scope" is the lexical area in which the

    > > definition is available; but if that's the case, the name "lexical

    > > scope" is a redundancy,

    > Only in the sense that indefinite scope can be understood as "lexical scope

    > extending to the whole of the program".

     Um... Why? I mean, I agree totally with that definition of indefinite

    scope, but it has absolutely zero to do with what I just said. Right?

    I'm at a loss to clarify myself, unfortunately. Obviously the words

    that seem so clear to me aren't so clear to you, and probably mean

    something entirely different. To begin with, I didn't use the term

    "indefinite scope"; I only examined "scope" and "lexical scope". My

    point was that if "scope" contains the idea of lexicality in its

    definition, then the term "lexical scope" is a redundancy, much like

    "lightless darkness".

     > > and "dynamic scope" is a contradiction in terms.

    > Rather, a shorthand expression for "dynamic extent and indefinite scope".

     That's what he claims. I have just attempted to explain why, if I

    accept his definition of "scope", it looks to me like a contradition

    in terms. Perhaps a better term would be an "oxymoron".

    If scope is the _lexical_ area within which a variable can be referred

    to, but the variable is dynamicly defined, then there IS no lexical

    area within which it can be referred to -- by this definition of scope

    (which I find useless) dynamicly defined variables _have_ no scope.

    Now, Lisp does things in a way that camoflauges the uselessness of

    this definition. In Lisp, every symbol can be used everywhere, which

    means that dynamic variables appear to have _infinite_ scope rather

    than the zero scope that his strict definition would require.

     > > Oh, and he defines "extent" as the time over which a definition

    > > is available; but I don't see how that would ever be useful, since

    > > there's no such thing as "static extent" in those terms, and dynamic

    > > extent is uncomputable.

    > Extent can be either dynamic or indefinite ("static extent" indeed makes

    > no sense), and we can define indefinite extent as "extent from the dynamic

    > start of execution to the dynamic end of execution".

     Right; this does make sense. Or even more practically, "extent from

    the creation of the thing to the destruction of the last reference to

    it." Extent definitely requires a garbage collector or other runtime

    mechanism.

     > > In summary, I don't think that page really discusses the issue we're

    > > discussing; it addresses the specifics of how Lisp works (notice that

    > > it claims that dynamic scope is a misnomer simply because Lisp doesn't

    > > actually have dynamic scope, not because dynamic scope is impossible),

    > No, scope (as defined there) cannot be dynamic, because (as you point out)

    > scope has to do with the static program text.

     Okay, I think I can read the chapter now and have it make sense. You

    have to be careful, though, because the author is not making any

    attempts to define any terms; he's only explaining what Lisp does.

    This is especially clear when he claims that "dynamic scope is

    actually dynamic extent and infinite scope". This is only true for a

    language for which ALL symbols are treated as referring to variables

    with infinite scope. Without taking that special measure, by his

    "definitions" dynamic scope would actually be zero scope.

     > "Well, I'm back."  --Sam        John Cowan <jcowan@...>

     -Billy

## Ivan Tomac — 2005-03-20 14:33:38

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr"

    <wtanksleyjr@g...> wrote:

     > > You cannot redefine anything - the language does

    > > not allow mutable variables.

    >

    > Wait, you're now saying that no name in the source can ever be

    > assigned to a value once it's been previously assigned? So once I

    > assign 3 to the symbol x, x will only and exclusively have the value

    > 3, no matter what happens? Nobody else can ever define a variable or

    > function using the symbol 'x' ever again?

    >

    > If this is true, it's the most restrictive proposal I've ever heard.

     No because that is exactly how let expressions work. They do not allow

    you to change existing bindings - you can only create new bindings.

    This is critical information - if you ignored that part then it's no

    wonder you're not understanding anything of what I'm saying.

    In Caml you can write

    let x = 3 ;;

    then you can use x in some expression, E, or a function F and then

    rebind x afterwards:

    let x = 5 ;;

    E and F will continue using the old binding. That's because the

    previous binding of x did not change - a new binding was created

    instead.

    In the same way in this imaginary concatenative language you can

    write:

    [x 3] DEF2

    followed by an expression, or a new function definition that uses x,

    followed by rebinding of x

    [x 5] DEF2

    It is exactly the same as in Caml or SML.

    Note that in Caml you can't have a let expression that escapes the

    scope of it's parent let expression - that is why it's called static

    nested scoping - nesting affects scope in Caml but not in all

    statically scoped languages.

     > Just so we understand: I can't, of course, do that. I never claimed

    > to. I claimed that the dynamic (runtime) definitions you were

    > proposing would interfere with textual manipulations in the same way

    > that mutable variables do.

     By saying that you're effectively saying that you can simulate mutable

    variables somehow in such a language. How? Although I guess there is

    no point in asking at this point considering you misunderstood what I

    said about how the language works.

     > > But that only affects newly entered definitions, not existing

     ones -

     > > how can you change the meaning then?

    >

    > _Textually_, there is no difference between "newly entered" and

    > "existing" definitions. If two identical words at the same lexical

    > level have different meanings due to dynamic operation of the

    > language, the compiler cannot use static analysis.

     But two identical words within a quotation have the same meaning - at

    compile time the environment is static, I keep saying that over and

    over again and you keep ignoring that - all the bindings are known and

    it is known that they will not change in the future. New bindings do

    not replace old ones - they simply make them inaccessible to the

    programmer but not to the quotations that use them.

     > You just described conditional compilation. That's dynamic. I show

    > below that loops can also dynamicly change the final values bound to

    > variables. The compiler can't pretend the definitions are static; in

    > static terms, the compiler can't know which definition will be

     chosen

     > from the IF.

     Read below.

     > Okay, here's an example.

    >

    > [x 0] DEF2

    > [x [x 1] DEF2]

    > [x [x 2] DEF2]

    >    i swap i

    >

    > This should produce (0 1) on the stack, unless I got that wrong.

     Now,

    Actually you did get it wrong - it would produce 0 0 on the stack.

    Why? Because both quotations were compiled at the time when the

    binding of x was 0.

    The following would have produced 0 1:

    [x 0] DEF2

    [x [x 1] DEF2] i

    [x [x 2] DEF2] i

    or

    [x 0] DEF2

    x [x 1] DEF2

    x [x 2] DEF2

     > by concatenative theory, you should be able to concatenate those two

    > quotations together, and get the exact effect of calling them one

    > after the other (the swap, of course, just buries the first

     function's

     > result and gets at the address of the second function, so the

    > concatenation shouldn't change the final result):

    >

    > [x 0] DEF2

    > [x [x 1] DEF2 x [x 2] DEF2]

    >    i

    >

    > Now the result is (0 0).

    >

    > The result has changed, but nothing's happened that should be

    > violating concatenativity, so the result shouldn't change.

    >

     You may have a point that if that was rewritten as [x [x 1] DEF2 x [x

    2] DEF2] the result would again be 0 0. So maybe it does break

    concatenative properties of the language a bit (which would finally

    explain why Joy separates defining words from the rest of the

    language) but I don't think it matters that much because compile and

    run cycles are still separated (although the distinction isn't as

    obvious as it is in Joy) - if compile time and run time are looked at

    separately then the concatenative properties of the language hold. In

    other words:

    [x [x 1] DEF2] [x [x 2] DEF2] [i] dip i

    is the same as

    [x [x 1] DEF2 x [x 2] DEF2] i

    but not

    [x [x 1] DEF2] i [x [x 2] DEF2] i

    because the environment has changed before the 2nd quotation has been

    compiled.

     > > I said no such thing.

    >

    > Actually, that's what you said, and what you say below.

    >

    > > I said that words that have not been defined can be handled in two

    > > ways - I said I personally prefer the way where undefined

     bindings get

     > > compiled in anyway

    >

    > Okay, and then what happens? "Undefined results"? No, you expect the

    > programmer to define the name before the code gets run. You said so

    > yourself. And when the code is run, THEN the undefined word will

     take

     > on the current meaning. Who decides what the current meaning is? Not

    > the compiler, since the compiler only knows what was defined at the

    > time the word was used. Here's an example:

    >

    > Assume "print" is defined to print a number. x is not defined.

    > [getx x] DEF2

    > [x 0] DEF2

    > [getx [x getx 1 +] DEF2] 3 times

    >

    > (I'm not fluent in Joy -- I probably got "times" wrong. Please

     assume

     > it works the way I wrote it.)

    >

    > That code will leave (0 1 2) on the stack and x will be 3, if I read

    > your proposal right, because the 'x' in 'getx' has to be rebound

     when

     > it's executed. This has the FULL effect of a mutable variable.

    >

     No I did not once mention that the binding that was undefined but

    still compiled into a quotation would later be redefined. You assumed

    it would have been redefined.

    For all you know the binding could have remained undefined. And that

    is exactly the case - considering how many times I said that existing

    bindings cannot change I thought it was obvious that that included

    undefined bindings. Think lazy evaluation - you can have infinite

    loops, undefined bindings, etc. As long as you never hit that point in

    code during execution you won't get any errors. And quotations are

    lazy - they delay evaluation.

    I have no idea how you got this out of all the stuff I've said so far

    especially considering the emphasis I've placed on static bindings and

    how the meaning of bindings inside quotations cannot change.

     > > I never said anything about dynamic (re)definition of words. In

     fact I

     > > keep pointing over and over again that you cannot re-define words

     at

     > > run-time - you can only create new bindings - the existing ones

     remain

     > > intact. For the purpose of compiling new definitions only the most

    > > recent binding is used.

    >

    > Irrelevant. The old binding is no longer available. Thus, the symbol

    > has been redefined. No, that redefinition is not retroactive (as it

    > would be with mutable variables or dynamic binding), but its scope

     is

     > not fixed to any lexical area; its scope depends entirely on how the

    > program's execution flows.

    >

     Oh but the old binding IS available. Just not visible to the

    programmer. All the quotations that have been defined before the new

    binding was created continue to use the old binding! I keep saying

    that over and over again but you keep missing this. It is for this

    reason that I keep comparing this to let expressions.

    I'm somewhat puzzled as to how you came to that conclusion as pretty

    much every example I've provided in the last few posts shows otherwise

    - that old bindings are preserved.

    Example from one of my past posts (one of few, all of which illustrate

    this):

    [a 3] DEF2

    [b a] DEF2

    [a [a 4] DEF2 a] i a b

    and on stack you end up with 3 3 4 3

    Did you notice that 'b' kept the old binding even after 'a' has been

    redefined?

     > > No - compilation proceeds one top-level quotation at a time. In

     other

     >

    > Ah, okay. So my second guess was better than my first. Sorry.

    >

    > > Redefinitions are not redefinitions until run-time (in fact

     they're

     > > not redefinitions at all - they create new bindings, don't change

    > > existing ones).

    >

    > Pardon, but they ARE redefinitions. They don't change past uses of

     the

     > bindings, but they DO change the meaning of the text.

    >

    > > > that rule is antithetical to lexical scoping; in lexical scoping

    > > > definitions only affect stuff _contained_ within the

     definition's

     > > > lexical body, while by this rule definitions only can affect

     stuff

     > > > not

    > > > contained within the lexical body that contains the definition.)

    >

    > > That's exactly the rule I'm using and no, it does not conflict

     with

     > > the definition of static scoping (it conflicts with the

     definition of

     > > static nested scoping however but not static scoping!).

    >

    > According to FOLDOC, the two mean the same thing. Nested scoping

     just

     > means that you can redefine a word and when you undefine it the old

    > word will still be there. That's pretty much a requirement of

     lexical

     > scoping; in fact, FOLDOC wasn't able to come up with any examples of

    > lexical scoping that weren't also nested lexical.

    >

     No they do not mean the same thing - nested static scoping is simply

    one way to implement static scoping.

    Also note that what you've just described is both dynamic and static

    nested scoping - to be more specific dynamic scoping also allows you

    to redefine a word and when you undefine it the old word will still be

    there. One crucial difference that you missed is that in case of

    static scoping, the previously defined functions that used the old

    binding will keep using the old binding even within the scope of the

    new binding while in case of dynamic scoping previously defined

    functions will use the new binding within the scope of the new

    binding.

    The language I've described is an example of a statically scoped

    language that is not affected by nesting (the kind of a statically

    scoped language that FOLDOC did not have an example for). Read below.

     > > As I've already mentioned defining a word is not neccessarily the

     same

     > > as compiling

    >

    > I don't know why you mention it; it appears to have no relation to

    > anything I've ever said.

    >

     It has everything to do with what we've been talking about. Scoping in

    particular.

    There is no reason to assume that just because a binding does not

    happen at compile time that it isn't static. We've already agreed that

    bindings can be static and still happen at run-time. Dynamic bindings

    (as in bindings that change at run-time) are a requirement for dynamic

    scoping. In the absence of dynamic bindings the language can be

    nothing else but statically scoped.

     > > To put it another way - there are only two forms of scoping -

     dynamic

     > > and lexical/static - if this isn't dynamic scoping then it can

     only be

     > > static/lexical and it isn't dynamic scoping (hopefully I'll

     eventually

     > > manage to convice you of that).

    >

    > I don't see how. It's definitely dynamic, since it happens at

     runtime.

     > See http://foldoc.hld.c64.org/foldoc.cgi?lexical+scope for

     definitions

     > that work for me.

    >

     That's exactly the same definition of lexical/static scoping I've used

    few posts ago.

    Have a look at the definition of dynamic scoping:

    http://foldoc.hld.c64.org/foldoc.cgi?dynamic+scope

    Note the part that says "an identifier can be referred to, not only in

    the block where it is declared, but also in any function or procedure

    called from within that block, even if the called procedure is

    declared outside the block". That is not the case here.

     > > > [current-item 4] DEF2

    > > > [0] [[current-item [current-item 8] DEF2] times] infra

    > > > current-item

    >

    > > > Notice that the definition is now being executed zero times? Now

    > > > what

    > > > happens? I'd expect [] 4.

    >

    > > Correct.

    >

    > But see the problem? The empty list is fine, because it's obviously

    > the result of the normal operation of infra and time; but the 4 is

    > totally unexpected. The compiler cannot staticly guess that it

     should

     > be 4. Lexically, there was a definition preceding it that should

     have

     > changed it to 8; but dynamicly the program chose not to execute that

    > definition.

     Yes but you're missing the point that only quotations are compiled -

    everything else is executed. Therefore compiler only worries about

    quotations.

     > > Note that that is exactly the same as this:

    > > [current-item 4] DEF2

    > > [0] [[current-item] times] infra current-item

    >

    > Except for the lack of any definitions, right? Since that's what

     we're

     > discussing, I think that's a pretty painful omission.

     No, it's exactly the same - when you supplied 0 as an argument to

    times whatever was inside the quotation would not have been executed.

    DEF2 is just another word that causes a side-effect that affects the

    rest of the environment - much like put or print would.

     > > while the former can be rewritten as:

    > > [current-item 4] DEF2

    > > [5] [[current-item] times] infra

    > > [current-item 8] DEF2

    > > current-item

    >

    > What if the [5] were dynamicly chosen -- for example, from user

     input,

     > or read in from a file?

     What if a programmer in Joy's repl loop types [4] instead of [5]? Does

    it matter? Neither affects anything that has already been written or

    typed or compiled or executed or defined - only affects things that

    haven't been compiled yet (or in case of a repl loop potentially

    things that haven't been evaluated yet). Read bellow.

     > > > The problem would be even worse if the

    > > > intial definition of current-item were missing, but I'm sure you

    > > > expect that.

    >

    > > > Now what:

    >

    > > > [current-item 4] DEF2

    > > > [5] [[current-item [current-item current-item 1 +] DEF2] times]

    > > > infra  current-item

    >

    > > > Interestingly, this produces [4 4 4 4 4] 5, right?

    > > >Oh, and also; if

    > > > you undefine current-item, you'll find that the old value was 5

     as

     > > > well, since there are actually 5 new definitions.

    >

    > You didn't respond to the example, in which the value of

     current-item

     > mutates to 5.

     Sorry about that - yes, [4 4 4 4 4] 5 is correct.

    The part about undefining current-item is wrong as there is no way to

    undefine it. And it if hasn't been defined initially it'll either

    cause an error at compile time (in case undefined bindings are

    rejected at compile time) or it will give you an error message when

    you try to run the quotation using infra and then another error when

    you try to execute current-item afterwards considering that the

    quotation failed to execute and create a binding for current-item.

     > > > You'd expect this to be identical to the original program,

     right?

     > > > [current-item 4] DEF2

    > > > [[current-item [current-item current-item 1 +] DEF2] times]

    > > >     [current-item] swap infra

    > > > Problem! This isn't the same as the original anymore.

    >

    > > Problem is that you're assuming compilation happens on a

     line-by-line

     > > basis. Read above.

    >

    > My explanation did assume that. But the program as written does show

    > what I wanted to show, that a "safe" manipulation is actually

     unsafe.

     > Exchanging two quotations in the source and then inserting a swap

    > should produce the same result; but if the second quotation gets

    > executed first and includes a redefinition of a variable in the

     first

     > quotation, the redefinition changes how the second quotation gets

    > compiled.

    >

     But that is not the case. Read above.

     > No, you haven't addressed it; you just claimed I was wrong, and then

    > when you tried to explain you stopped the explanation exactly when

     you

     > were about to say what happens when the word is run (which is the

    > whole dispute).

     My apologies. I thought it was clear that when I said that bindings

    cannot be redefined or undefined that that includes bindings that have

    not been defined yet. In other words a binding that has not been

    defined and has been compiled into a quotation (assuming it isn't

    rejected at compile time) will remain undefined forever.

     > Here's exactly what you claim happens: If the symbol is undefined at

    > compile-time, it gets compiled anyhow; in that case, the user/client

    > is expected to define the word before running it; if they fail to do

    > so, running the word will produce an error. If they do define the

    > word, running the word will produce the behavior using the new

    > definition.

    >

    > I just realised that you left an ambiguity there, so what I thought

    > you meant might not be what you actually meant. I thought you meant

    > that when the word is run, the system looks through the environment

     to

     > try to find an apprpriate definition for the word that wasn't known

     at

     > compile time. However, you may actually have meant that whenever a

    > word is defined for the first time, the system searches all words to

    > try to find any formerly unknown uses of that word, and it

     permanently

     > corrects them to match the new definition.

    >

    > Is that what you meant?

     No, neither is correct.

    I'm not sure where you see the ambiguity. I've stated a number of

    times that the code or quotation that has already been compiled cannot

    see any new bindings - only bindings that were present when the

    quotation was compiled.

    I've even tried to explain it in a different way - that the state of

    the current environment gets associated with a quotation that is

    currently being compiled and that that is the environment out of which

    that quotation extracts bindings - not some other environment that may

    or may not have gained new bindings between the time when the

    quotation has been compiled and when the quotation was executed.

    Maybe the problem is that it wasn't clear what I meant by bindings.

    Ironically I chose to use the term binding names to values and avoided

    making references to variables specifically to avoid any ambiguity. In

     particular I thought that the references to let expressions would

    have at least hinted at what I meant by bindings.

     > > > > That's because no restrictions are necessary as it's lexically

    > > scoped

    > > > > and doesn't allow mutable variables.

    >

    > > > Non sequitur. Lexical scoping isn't meaningful for your

     language as

     > > > you've described it (your language is definitely NOT lexically

    > > scoped,

    > > > as I've shown above, since new definitons are NOT available

     within

     > > the

    > > > block in which they lexically appear), and mutable variables

     have

     > > > nothing whatsoever to do with the problem.

    >

    > > Read above.

    >

    > This paragraph stands on its own. Your language is prima facia not

    > lexically scoped, because new definitions are not confined to their

    > lexical context; instead, they follow the dynamic flow of control

    > wherever it leads.

     Alright... another attempt to clarify just how and why this language

    is statically scoped and not dynamically scoped. Have a look at the

    following quotation:

    [[x 4] DEF2]

    It does not define anything. It is a list containing another list and

    a symbol - on it's own it does nothing. It is not a definition.

    Once it's executed however it binds x to 4.

    Now this is very important: the only thing that is ever compiled are

    quotations! Everything else that occurs at the top-level is executed.

    In the context of a repl loop the quotation above is a function that

    modifies the environment for all the other quotations that are defined

    afterwards.

    You can do exactly the same thing using let expressions in Caml or

    SML. In Caml let expression takes two forms and the second one is just

    a special case of the first one:

    1. let x = 3 in x ;;

    2. let x = 3;; x ;;

    The scope of the second one encompasses EVERYTHING that follows in the

    source text up until the end of input or the point where x is bound to

    another value while the scope of the first one extends only until ;;

    The only difference is in how Caml handles nesting. The scope of a

    nested let expression in Caml exists only within the scope of it's

    parent let expression.

    In the hypothetical concatenative language I've described that is not

    the case - nested definitions, if executed, will create permanent

    bindings of which the scope extends all the way to either the end of

    input or the point where a new binding with the same name is created.

    In the context of an external compiler think meta-programming.

    Quotations are compiled, everything else that occurs at the top level

    is executed. Finally you could bind a symbol such as main to a

    quotation to make that an entry point for the final program.

    Even if main (or any other words it calls) does contain any DEF2s

    inside, in this context they are completely meaningless and the

    compiler can simply treat them as dead code as new bindings do not

    affect existing quotations and upon the completion of main's execution

    the control returns to the operating system.

     > > > The restrictions that would help would include things like:

     "dynamic

     > > > definitions can only be used in runtime code, not inside of a

    > > > definition." That one requirement would ease all of the

    > > > restrictions.

    >

    > > But there are NO dynamic definitions! Bindings occur at run-time

     but

     > > they are completely static! You cannot change them once they have

    > > been created.

    >

    > You're confusing bindings and definitions. I don't blame you; I did

    > too, and I had to be corrected.

    >

    > > > > Bindings can be static and still happen at run-time. Dynamic

    > > binding

    > > > > would imply that the binding itself can be changed which is

     not

     > > the

    > > > > case here. A new binding gets created in the environment but

     all

     > > the

    > > > > old bindings, even the ones with the same name are preserved.

    > > >

    > > > I apologise; you're right. My confusion, my fault.

    >

    > > Ah, but you still insist that the language is dynamicly scoped

     even

     > > though the bindings are static! Do you not see that all the

     compiling

     > > happens at compile time (therefore there is no need for a run-time

    > > compiler) but all the bindings happen at run-time and are static?

    >

    > Your bindings are being made at compile-time, not run-time. This is

    > why they're called static bindings. But your definitions are being

    > made at runtime; this is why your language has an ordinary library

    > function, DEF2, which creates a definition at the time it's run.

     This

     > is why your definitions are dynamic.

    >

    > Your language is dynamicly scoped because the scope of the variables

    > DEF2 creates can only be discovered by discovering the dynamic flow

     of

     > control.

    >

     I'm confused - what do you consider a definition and what a binding?

    Bindings occur at run-time. Defining new words occurs at run-time. The

    only thing that that happens at compile time is compiling quotations.

     > > You cannot change existing bindings and you cannot undefine

     existing

     > > bindings. You can only create new ones and they only only affect

     newly

     > > defined quotations much like binding a name to an expression in a

     let

     > > expression will only affect the code that follows the binding.

    > > How can the language be dynamically scoped then?

    >

    > These questions are all questions about binding, not scoping. Thus

    > your last question cannot be answered by referencing any of them.

     Actually they are about scoping because scoping affects binding and

    binding depends on scoping. I thought the example at the end of my

    last post illustrated that. If not then here's a link to another

    example: http://www.n-a-n-o.com/lisp/cmucl-tutoria

    ls/LISP-tutorial-12.html

     > Oh, by the way, there's no action "undefine an existing binding".

    > Bindings can't be defined or undefined. Definitions get defined;

    > bindings get bound.

     What do you consider a definition? To me a definition is a name bound

    to a value.

     > > No, and I will again point out that compiling quotations/code and

    > > binding a name are not the same. They are two disctinct operations

    > > even though most languages don't treat them as such. Binding

     always

     > > happens after compiling.

    >

    > I'm seriously confused why you're saying this. It seems totally

    > irrelevant to what I'm saying. There also seems to be a confusion --

    > when you say "binding always happens after compiling" I suspect that

    > you mean "definition always occurs after compiling".

    >

     It isn't irrelevant. You said that definitions do not become available

    until after they've left the lexical scope which is not true. As I've

    already explained above [[x 4] DEF2] does nothing. The definition

    inside does not occur until you execute the quotation. The point in

    the code where you execute the quotation is the beginning of the

    lexical scope of the definition.

     > > No - what you are referring to in this case would be conditional

    > > compilation. I should state that in this case 'compilation' is a

     bit

     > > misleading as it's really just conditional binding of names but

     the

     > > traditional term is conditional compilation.

    >

    > Conditional _definition_ of names. AKA dynamic definition.

    >

     I don't think that's the case - I think you're limiting the definition

    of static scoping to static nested scoping.

     > > Dynamic scoping has nothing to do with that - dynamic scoping

     would

     > > mean that once I bind 'a' to say 3, and use it within 'b', and

     then

     > > later yet use 'b' within 'c' which redefines 'a' to 5, 'b' would

     use

     > > 'a' as if it has been defined as 5 to start with.

    >

    > No, that's dynamic binding (because already-known bindings in

    > previously compiled words have to be changed to match new

    > definitions).

    >

    > Dynamic scoping is different-- in dynamic scoping there's no

     guarantee

     > that you'll be able to access a defined name from any place in the

    > source text. Instead, the guarantee is that you'll be able to access

    > the defined name chronologically after the definition has been

    > executed.

    >

     I will again point you at

    http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-12.html

    Also have a look at how dynamic scoping is defined at FOLDOC.

    Especially the part that I've already mentioned in this post and that

    states "an identifier can be referred to, not only in the block where

    it is declared, but also in any function or procedure called from

    within that block, even if the called procedure is declared outside

    the block".

     > > That's a bit confusing so I'll illustrate that with an example:

    > >

    > > [a 3] DEF2

    > > [b a] DEF2

    > > [c [a 5] DEF2 b] DEF2

    > > c b

    > >

    > > and on stack you end up with 5 3 - that's what would happen in a

    > > dynamically scoped language (recall that the scope in dynamically

    > > scoped languages depends on the nesting of function calls at

    > > run-time).

    > > In a statically scoped language I'm trying to describe the above

     code

     > > would put 3 3 on stack.

    >

    > That's static binding, definitely.

    >

    > If it were static scoping, the DEF2 inside the body of 'c' would

     only

     > change the value of 'a' within a staticly fixed area -- usually the

    > quotation within which the definition appears. Joy is a good example

    > of this; Joy definitions can be lexically scoped, and when they do

     so,

     > you can use them only within the libra for which they're defined.

     Ah again - that is true for static nested scoping, not necessarily

    static scoping!

     > > dynamically scoped language (recall that the scope in dynamically

    > > scoped languages depends on the nesting of function calls at

    > > run-time).

    >

    > That's a true statement, but painfully inadequate as a definition.

     The

     > reason for the unclarity is the statement "the nesting of function

    > calls at runtime". It's so unclear to you what this means that when

    > you tried to give me an example, your example contained only one

    > nested function call (the call from c->b->a), and that nested call

    > didn't contain any definitions (so it couldn't possibly be a

    > demonstration of this statement).

     How is it not a demonstration of the statement?

    'a' is first defined as 3.

    'b' is defined as 'a'.

    At run-time 'c' redefines 'a' as 5 and calls 'b'.

    When 'c' terminates the previous definition of 'a' is restored and 'b'

    continues using that definition.

    So the execution of 'b' varies depending on whether it's nested inside

    of 'c' or whether it's called from outside of 'c'.

     > The scope of a definition in a dynamicly scoped language begins

     *when*

     > a definition is executed. The scope of a definition in a lexically

    > scoped language begins *where* the definition appears in the source.

    > See the difference?

     I don't know if I agree with that. In a dynamically scoped language

    when the definition is executed it changes existing bindings - in a

    statically scoped language it does not (your definition of static

    scoping only includes nested static scoping).

     > -Billy

     Ivan

## sa@dfa.com — 2005-03-24 17:04:21

    compute the partitions of an integer.  e.g.

          5 partition

    [[5]

     [4 1]

     [3 2]

     [3 1 1]

     [2 2 1]

     [2 1 1 1]

     [1 1 1 1 1]]

    test:

          20 partition length

     627

## phimvt@lurac.latrobe.edu.au — 2005-04-04 07:12:09

    On Thu, 24 Mar 2005 sa@... wrote:

     > compute the partitions of an integer.  e.g.

     [..]

    Nice problem. I immediately wrote a Joy program which would have

    run, but even before I got to type it in I recognised that it

    would have produced the  wrong output. So I started again from

    scratch - trying to understand what the problem really was.

    This is how far I got:

    I initially conceived of the problem as involving induction

    of some sort: from the answers to (n), develop the answers

    to (n+1). It looked rather like Pascal's triangle at first,

    but later I saw that we need a sort of stack of triangles,

    written, if you like, on sheets of acetate film. The first

    three triangles are shown below. I recognised the need for

    further triangles from the fact that the first triangle was

    incomplete in row 4, and the need for a third triangle comes

    in row 6. The notation is important: 3211 means one 3, one 2,

    two 1's. Note THE PATTERN: going diagonally down to the

    left, we increment the first number, going diagonally down

    to the right we append a 1.

    n:   f i r s t    s h e e t               second sheet         third

    1:             1

    2:          2     11

    3:        3    21     111

    4:      4   31    211    1111                  22

    5:    5   41  311   2111   11111            32   221

    6:  6  51  411  3111  21111  111111       42  321  2211          33

    This suggests that for even n we must start a new sheet with a new

    triangle with the apex of the form nn. I have no way of knowing whether

    this will complete all rows (or are they really triangles stand up).

    I cannot spend more time on this. And I won't try to write a Joy

    program until I know that I have the pattern right.

    How am I doing, oh Master?

    I am now going to google for help.

      - Manfred

## Michael Pruemm — 2005-04-04 08:17:06

    On Apr 4, 2005 9:12 AM, phimvt@...

    <phimvt@...> wrote:

     > 6:  6  51  411  3111  21111  111111       42  321  2211          33

     And don't forget

    6: ... 222

    This would be another sheet in your pattern.

    - Michael

## sa@dfa.com — 2005-04-04 13:37:48

    phimvt@... wrote on 04/04/2005 03:12:09 AM:

     >

    >

    > On Thu, 24 Mar 2005 sa@... wrote:

    >

    > > compute the partitions of an integer.  e.g.

    >

    > [..]

    >

    > Nice problem. I immediately wrote a Joy program which would have

    > run, but even before I got to type it in I recognised that it

    > would have produced the  wrong output. So I started again from

    > scratch - trying to understand what the problem really was.

    > This is how far I got:

    >

    > I initially conceived of the problem as involving induction

    > of some sort: from the answers to (n), develop the answers

    > to (n+1).

     that's also the way i started thinking about it.  here's

    the algorithm i settled on (with some help from a collection

    of combinatorial routines written in fortran):

    the algorithm starts with the unit list [n] and ends with

    a list of n 1s.  e.g. [7] -> [1 1 1 1 1 1 1].  given a

    list v, the algorithm produces its successor.  for example,

    suppose in the course of generating the partitions of 7,

    you have v

          [3 2 1 1]

    compute the successor list p^d^r as follows:

    i = the index of the smallest part > 1

    k = that part minus 1

    p = everything up to but not including that part

    s = the sum of everything following and including that part

    m = s mod k

    j = s / k (i.e. integer division of s by k)

    r = the remainder of [m] or [] if m is 0

    d = a list of j-many copies of k

    return p^d^r

    so the successor of v is:

    i = 1

    k = 1 = 2-1

    p = [3]

    s = 4

    m = 0

    j = 4

    r = []

    d = [1 1 1 1]

    return [3]^[1 1 1 1]^[] = [3 1 1 1 1]

    my k implementation (i haven't attempted to write one in a

    concatenative language) is:

    part:{[v]

     if[0>i:-1+(v>1)?0;:v]  / index of smallest part>1

     k:-1+v i               / that part-1

     p:i#v                  / prefix

     s:+/i _ v              / sum of suffix

     if[~r:s!k;r:()]        / remainder if not zero

     d:(_ s%k)#k            / distribute components

     p,d,r}\,:              / all

    e.g.

      part 7

    (,7

     6 1

     5 2

     5 1 1

     4 3

     4 2 1

     4 1 1 1

     3 3 1

     3 2 2

     3 2 1 1

     3 1 1 1 1

     2 2 2 1

     2 2 1 1 1

     2 1 1 1 1 1

     1 1 1 1 1 1 1)

    hardly the most intuitive algorithm i've ever seen!  your

    recursive-triangles approach seems more promising, at least

    as a way of producing that sense "inner conviction" of

    the method's correctness.

    It looked rather like Pascal's triangle at first,

     > but later I saw that we need a sort of stack of triangles,

    > written, if you like, on sheets of acetate film. The first

    > three triangles are shown below. I recognised the need for

    > further triangles from the fact that the first triangle was

    > incomplete in row 4, and the need for a third triangle comes

    > in row 6. The notation is important: 3211 means one 3, one 2,

    > two 1's. Note THE PATTERN: going diagonally down to the

    > left, we increment the first number, going diagonally down

    > to the right we append a 1.

    >

    > n:   f i r s t    s h e e t               second sheet         third

    >

    > 1:             1

    >

    > 2:          2     11

    >

    > 3:        3    21     111

    >

    > 4:      4   31    211    1111                  22

    >

    > 5:    5   41  311   2111   11111            32   221

    >

    > 6:  6  51  411  3111  21111  111111       42  321  2211          33

    >

    > This suggests that for even n we must start a new sheet with a new

    > triangle with the apex of the form nn. I have no way of knowing whether

    > this will complete all rows (or are they really triangles stand up).

    > I cannot spend more time on this. And I won't try to write a Joy

    > program until I know that I have the pattern right.

    >

    > How am I doing, oh Master?

    >

    > I am now going to google for help.

    >

    >   - Manfred

    >

    >

    >

    >

    > Yahoo! Groups Links

    >

    >

    >

    >

    >

    >

    >

## janvanlent — 2005-04-04 14:40:38

    Some interesting links.

    http://www2.toki.or.id/book/AlgDesignManual/BOOK/BOOK4/NODE153.HTM

    Elegant program in Python:

    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/218332

    Iterative programs in Python:

    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/221132

    http://www.livejournal.com/users/dandrake/66219.html

    jan

## icpdesign — 2005-09-20 20:39:01

    I am ventoring here, i do not have sound theroetical knowledge about language models.

    But, it seems to me that languages with dynamic scoping are very difficult to implement

    with parallel constructs.

    If at one point in time there is 2 concurrent threads running and both depends on a

    defined name n, and if one of the thread redefines the name n than what happens in the

    other running thread? what value of n it should use. You may find a protocol to this, but

    then compare this with sequential running; in sequential mode it is sound to think that as

    soon as you redefine the name n, then all subsequent quotations see the new value of the

    name n.

    So dynamically scoped languages are non-determinist; since the result of redefining

    names may give different results in different runs with the same input.

    A picture, because i know i am most of the time i am not precise in my writing:

    DEFINE

    a == 1.

    in Parallel:

    scenario 1:

    -----------------------------------------------------------> time

           ...   [................... [a 2] DEF ...] # thead 1

                 [.... a ...] ...                         # thread 2

                       ^ here a = 1

    scenario 2:

    -----------------------------------------------------------> time

           ...   [... [a 2] DEF ...] # thead 1

                 [....................... a ...] ...                         # thread 2

                       ^ here a = 1

    in Sequence

           ... [... [a 2] DEF ...] [... a ...] ...

                                               ^here a should be seen as equal to 2

    comments are very welcome

    Taoufik Dachraoui

     --- In concatenative@yahoogroups.com, "William Tanksley, Jr" <wtanksleyjr@g...> wrote:

    > Ivan Tomac <e1_t@y...> wrote:

    > > For some strange reason some of the recent posts to this message board made

    > > me dig through the archives and re-read some of the old posts as well as go

    > > through most of the papers on Joy again.

    >

    > Hey, I did that too :-). It's almost worth being proven wrong to see

    > the traffic on the list pick up :-).

    >

    > > (http://www.latrobe.edu.au/philosophy/phimvt/joy/faq1.html) Manfred talks about

    the

    > > reasons why having defining words avaliable at run-time is a bad idea. The

    > > reason he states in the end is one relating to creation of variables that act the

    > > same way as they would in imperative languages.

    >

    > That's not quite what he says -- he says that such definitions would

    > not act in a way he considers appropriate to functional languages.

    >

    > The reason that functional languages don't allow mutable variables is

    > because the variables in lambdas aren't mutable; thus, the languages

    > modify what they can do in order to more closely conform to their

    > models. Definitions in Joy are similar to variables in lambda

    > expressions.

    >

    > This is a reasonable choice, but not the only one.

    >

    > > I have one question and one (obvious) observation:

    > > 1) Wouldn't this only be a problem with dynamically scoped languages? If Joy

    > > was lexically scoped this wouldn't be an issue.

    >

    > Er... True, but not for the reason you're stating. A lexically scoped

    > language cannot possibly have defining words available at runtime, so

    > no issue. Lexical scope means that definition availability is

    > determined only by the static source text. If defining words were

    > available at runtime, we'd have dynamic scoping.

    >

    > With that said, there's nothing bad about dynamic scope and allowing

    > redefinitions.

    >

    > > Ivan

    >

    > -Billy

## icpdesign — 2005-09-20 21:23:02

    < i subsmit the message again because of the problem in the

    formating, sorry>

    I am ventoring here, i do not have sound theroetical knowledge

    about language models.

    But, it seems to me that languages with dynamic scoping are

    very difficult to implement with parallel constructs.

    If at one point in time there is 2 concurrent threads running

    and both depends on a defined name n, and if one of the thread

    redefines the name n than what happens in the other running

    thread? what value of n it should use. You may find a protocol

    to this, but then compare this with sequential running; in

    sequential mode it is sound to think that as soon as you

    redefine the name n, then all subsequent quotations see the

    new value of the name n.

    So dynamically scoped languages are non-determinist; since the result of

    redefining

    names may give different results in different runs with the same input.

    A picture, because i know i am most of the time i am not precise in my writing:

    DEFINE

    a == 1.

    in Parallel:

    scenario 1:

    ---------------------------------------> time

    ... [.......... [a 2] DEF ...] ---# thead 1

    [.... a ...] ... -----------------# thread 2

    ------^ here a = 1

    scenario 2:

    -------------------------------------------> time

    ... [... [a 2] DEF ...] ------------# thead 1

    [.................. a ...] -------- #thread 2

    --------------------^ here a = 2 or 1

    in Sequence

    ... [... [a 2] DEF ...] [... a ...] ...

    -----------------------------^ here a should be seen

    -----------------------------  as equal to 2

    Note: In the parallel scenario i assumed that the 2 quotations

    can run in parallel

    comments are very welcome

    Taoufik Dachraoui

     > --- In concatenative@yahoogroups.com, "William Tanksley, Jr" <wtanksleyjr@g...>

     wrote:

     > > Ivan Tomac <e1_t@y...> wrote:

    > > > For some strange reason some of the recent posts to this message board made

    > > > me dig through the archives and re-read some of the old posts as well as go

    > > > through most of the papers on Joy again.

    > >

    > > Hey, I did that too :-). It's almost worth being proven wrong to see

    > > the traffic on the list pick up :-).

    > >

    > > > (http://www.latrobe.edu.au/philosophy/phimvt/joy/faq1.html) Manfred talks about

    > the

    > > > reasons why having defining words avaliable at run-time is a bad idea. The

    > > > reason he states in the end is one relating to creation of variables that act the

    > > > same way as they would in imperative languages.

    > >

    > > That's not quite what he says -- he says that such definitions would

    > > not act in a way he considers appropriate to functional languages.

    > >

    > > The reason that functional languages don't allow mutable variables is

    > > because the variables in lambdas aren't mutable; thus, the languages

    > > modify what they can do in order to more closely conform to their

    > > models. Definitions in Joy are similar to variables in lambda

    > > expressions.

    > >

    > > This is a reasonable choice, but not the only one.

    > >

    > > > I have one question and one (obvious) observation:

    > > > 1) Wouldn't this only be a problem with dynamically scoped languages? If Joy

    > > > was lexically scoped this wouldn't be an issue.

    > >

    > > Er... True, but not for the reason you're stating. A lexically scoped

    > > language cannot possibly have defining words available at runtime, so

    > > no issue. Lexical scope means that definition availability is

    > > determined only by the static source text. If defining words were

    > > available at runtime, we'd have dynamic scoping.

    > >

    > > With that said, there's nothing bad about dynamic scope and allowing

    > > redefinitions.

    > >

    > > > Ivan

    > >

    > > -Billy