Why are local variables not respected?


In this code snippet, fields-types in the end is modified by the to-camel-case function, vs. being passed as a local variable to the parent function:

fields-types: ["First Name" "string" "Last Name" "string" "Age" "int"]

to-camel-case: function [name] [
    name/1: lowercase name/1
    replace/all name space ""

fill-template-body: func [
    field-labels-types [block!] /local vars fields-names-types
] [
  vars: [member-name member-type]
  field-names-types: copy []
  foreach [field-label field-type] field-labels-types [
      append field-names-types to-camel-case field-label
      append field-names-types field-type

fill-template-body fields-types

Execution gives:

>> fill-template-body fields-types
== ["firstName" "string" "lastName" "string" "age" "int"]
>> fields-types
== ["firstName" "string" "lastName" "string" "age" "int"]

Whereas I would want that fields-types to stay invariant:

fields-types: ["First Name" "string" "Last Name" "string" "Age" "int"]

Of course I can try to circumvent this by modifying to-camel-case to use a copy of name, but that is not something I think I should have to do.

Is there something like the var and val keywords in Scala?

Variable is an ugly word in REBOL, everything - even words - are values. This isn't some semantic newspeak, it's helpful in understanding the way in which REBOL flows.

I think of values as being contained within one giant array in memory, where REBOL (the language) uses words and their contexts to reference and interact with the values. Most REBOL functions operate without duplicating these values:

head lowercase next uppercase str: "abcd"
remove back tail str

This is one of REBOL's most efficient features - you don't need copies for intermediary processes, to require such is wasteful. Think of that array growing where every time you use replace, uppercase or to-camel-case a value is duplicated. Whole processes can be built on the premise of modification rather than duplication - indeed a context can be built without necessarily having to return a value:

remove-spaces: use [space mark][
    space: charset " ^-"
    [any [mark: space (remove mark) | skip]]

parse/all str: "Should Be No Spaces" remove-spaces

The trick then becomes knowing where to copy values, and I think happens to intersect with REBOL's gift for concise expression:

parse/all link: copy title: "An Article on REBOL" remove-spaces
print ["(" link ")" title]

to-camel-case copy field-label

And of course, modification has its limitations. Sometimes it is cleaner building from scratch.