Discussion:
Value Binding and Shadowing
(too old to reply)
duke
2012-05-26 13:20:56 UTC
Permalink
R. Harper in his book "Programming in Standard ML" (draft version)
states that "binding is not assignment". He then quickly asserts that
"we may shadow a binding by introducing a second binding for a
variable within the scope of the first binding." And, "The new binding
eclipses the old one, which may then be discarded since it is no
longer accessible."

Am I to understand that the _point_ to the above is that a _new_
variable is created, albeit with the same name, and that the old
variable (with the same name) is discarded? That, there is no re-
assignment going on, just a "nuke and bind" operation? Am I close?
Florian Weimer
2012-05-29 04:41:05 UTC
Permalink
Post by duke
R. Harper in his book "Programming in Standard ML" (draft version)
states that "binding is not assignment". He then quickly asserts that
"we may shadow a binding by introducing a second binding for a
variable within the scope of the first binding." And, "The new binding
eclipses the old one, which may then be discarded since it is no
longer accessible."
This description is slightly misleading. The previous binding might
still be reachable if a function has closed over it. It is possible
to explain this away, but the alternative (function definitions create
new bindings for all free variables in them for their own use) uses
something which is not textually represented, so I think it's worse.
Post by duke
Am I to understand that the _point_ to the above is that a _new_
variable is created, albeit with the same name, and that the old
variable (with the same name) is discarded? That, there is no re-
assignment going on, just a "nuke and bind" operation? Am I close?
"Nuke and bind" is misleading because of closures (see above) and the
fact that the types are not necessarily the same. Depending on the
representation, the implementation must choose a different spot. In
the end, this is an implementation detail, and it's best not to worry
to much about it.

I think the right mental model is to imagine little numbers next to
the identifiers which disambiguate them. Of course, this is a
nuisance, so this language feature is best avoided. Actual SML
programming practice is different, and this creates issues with
documentation tools: Which homonymous binding does the documentation
refer to?
duke
2012-05-29 17:56:30 UTC
Permalink
On Monday, May 28, 2012 10:41:05 PM UTC-6, Florian Weimer wrote:

[snip]
Post by Florian Weimer
I think the right mental model is to imagine little numbers next to
the identifiers which disambiguate them. Of course, this is a
nuisance, so this language feature is best avoided. Actual SML
programming practice is different, and this creates issues with
documentation tools: Which homonymous binding does the documentation
refer to?
Thanks for taking the time to reply to my question!! Much obliged...

Is this "shadowing" ambiguity (or "trip-wire" :D ) an SML-only issue, or is this prevalent in FP languages in general?
Jussi Piitulainen
2012-05-29 18:57:57 UTC
Permalink
Post by duke
[snip]
Post by Florian Weimer
I think the right mental model is to imagine little numbers next to
the identifiers which disambiguate them. Of course, this is a
nuisance, so this language feature is best avoided. Actual SML
programming practice is different, and this creates issues with
documentation tools: Which homonymous binding does the documentation
refer to?
Thanks for taking the time to reply to my question!! Much obliged...
Is this "shadowing" ambiguity (or "trip-wire" :D ) an SML-only
issue, or is this prevalent in FP languages in general?
The very first thing I ever heard of C was that C is a functional
programming language. That was almost thirty years ago; I don't think
I ever heard it said of C again. Anyway:

$ cat shadow.c
#include <stdio.h>

int main() {
char *foo = "outer";
puts(foo);
{
char *foo = "inner";
puts(foo);
}
puts(foo);
return 0;
}
$ gcc -Wall shadow.c
$ ./a.out
outer
inner
outer
$

It's a natural thing. (I wouldn't call it an ambiguity.)
duke
2012-05-30 00:52:47 UTC
Permalink
Post by Jussi Piitulainen
$ gcc -Wall shadow.c
$ ./a.out
outer
inner
outer
$
It's a natural thing. (I wouldn't call it an ambiguity.)
But isn't the "inner" foo a totally different memory address? Totally different "assignable" from "outer"?
Jussi Piitulainen
2012-05-30 06:05:17 UTC
Permalink
Post by duke
Post by Jussi Piitulainen
$ gcc -Wall shadow.c
$ ./a.out
outer
inner
outer
$
It's a natural thing. (I wouldn't call it an ambiguity.)
But isn't the "inner" foo a totally different memory address?
Totally different "assignable" from "outer"?
Yes.
Jeffrey Scofield
2012-05-30 06:23:10 UTC
Permalink
Post by duke
$ gcc -Wall shadow.c $ ./a.out outer inner outer $
It's a natural thing. (I wouldn't call it an ambiguity.)
But isn't the "inner" foo a totally different memory address? Totally
different "assignable" from "outer"?
Yes, but the objects are also totally different in ML, and any other
reasonable language with scoping. There's nothing especially strange
going on with scoping in ML, it's essentially the same as in C, or any
reasonable language since lambda calculus (1930s). Nested identical
names can be confusing, but the alternatives are worse, you don't want
to have allowed local names depend on global context.

Other things about ML are different from C (such as lack of
assignability to names). But scoping works the same, and is in fact
pretty "natural".
Dirk Thierbach
2012-05-30 10:28:30 UTC
Permalink
Post by duke
Post by Jussi Piitulainen
It's a natural thing. (I wouldn't call it an ambiguity.)
But isn't the "inner" foo a totally different memory address?
Totally different "assignable" from "outer"?
Which is exactly why shadowing is not something like
assignment. You're using the same name for two totally different
entities (no matter if they are mutable or not). And every decent
compiler for any language with statical scope will discard the outer
entity as soon as it is no longer usable (again, no matter if it is
mutable or not).

Hence, even though

let x = 2 in
let x = 3 in
...

might *look* similar to

x := 2;
x := 3;
...

it is not. The latter uses one mutable variable in a single scope, the
former two immutable "variables" with the same name in two nested
scopes.

- Dirk
Nobody
2012-05-30 14:40:06 UTC
Permalink
Post by Dirk Thierbach
Hence, even though
let x = 2 in
let x = 3 in
...
might *look* similar to
x := 2;
x := 3;
...
it is not.
Moreover, when using the interactive top-level,

val x = 2;
val x = 3;

corresponds to the first example (nested let) rather than the second
(sequenced assignments). E.g.:

- val y = 1;
val y = 1 : int
- fun addy x = x + y;
val addy = fn : int -> int
- addy 5;
val it = 6 : int
- val y = 2;
val y = 2 : int
- addy 5;
val it = 6 : int
-

Rebinding y has no effect upon addy, which continues to use the binding
which was in effect when it was defined.
Florian Weimer
2012-05-31 18:35:43 UTC
Permalink
Post by duke
Is this "shadowing" ambiguity (or "trip-wire" :D ) an SML-only
issue, or is this prevalent in FP languages in general?
Most languages with lexical scoping share the shadowing aspect.
What's different in SML is that the right hand side of a binding can
use the same name, refering to an earlier name. This applies to value
bindings and structure bindings:


structure S = MkS ()
structure S = Transform (S)

val v = mkValue ()
val v = transform v

This particular aspect of shadowing (and actual use in programming
styles) is pretty much restricted to SML and very close derivatives
(and for good reasons, IMHO).
Jeffrey Scofield
2012-05-31 19:24:30 UTC
Permalink
Post by Florian Weimer
What's different in SML is that the right hand side of a binding can
use the same name, refering to an earlier name.
This is a really good point. It makes the SML "let" a little different
from nested scopes in other languages.

It makes sense if you think of "let" as another notation for function
application

let x = <exp1> in <exp2>

=

(fn x => <exp2>) (<exp1>)

But this transformation maybe isn't so "natural" (at first?).

Thanks!

Jeffrey
duke
2012-05-31 19:41:07 UTC
Permalink
Post by Florian Weimer
Post by duke
Is this "shadowing" ambiguity (or "trip-wire" :D ) an SML-only
issue, or is this prevalent in FP languages in general?
Most languages with lexical scoping share the shadowing aspect.
Let take an example from Oberon-2 - a language that I'm familiar with:

MODULE whatEver;
VAR x, y: INTEGER;

PROCEDURE Outer;
VAR x, z: REAL;
PROCEDURE Inner;
VAR x, w: CHAR;
BEGIN
...
END Inner;
BEGIN
...
END Outer;

END whatEver.

x is defined in 3 different scopes! At any of these levels, only 1 version of x is visible at any one time. When in "Inner" x:INT and x:REAL can't be reached at all!

y is defined in the global scope and because it has zero competition, is never hidden.

z can be used by Outer and Inner, but is invisible to the module scope.

w is usable only in Inner.

The point is that I'm pretty sure that x are three different variables on the heap.

I realize that in FP "bindings" are more like constants in other languages. They're supposed to be immutable. So can you explain to me what this "shadowing" is in terms of the above Oberon example? It seems that I'm getting bogged down in the semantics of SML et al.
Jeffrey Scofield
2012-05-31 20:38:41 UTC
Permalink
Post by duke
MODULE whatEver;
VAR x, y: INTEGER;
PROCEDURE Outer;
VAR x, z: REAL;
PROCEDURE Inner;
VAR x, w: CHAR;
BEGIN
...
END Inner;
BEGIN
...
END Outer;
END whatEver.
x is defined in 3 different scopes! At any of these levels, only 1
version of x is visible at any one time. When in "Inner" x:INT and x:REAL
can't be reached at all!
. . .
The point is that I'm pretty sure that x are three different variables on the heap.
I don't see why you think things are any different in an FP language.
All the different values with the same name are different (though it
doesn't make a lot of sense to talk about a "location" for them).

let val x = 3 in let val x = 4.0 in ... end end

There are two different things named x. One has the value 3, the other
has the value 4.0. In the innermost scope (...), the outer x isn't accessible
by name, due to the shadowing. But the outer x still "exists". (Others
have posted code demonstrating this.)

If you must have "locations", you can replace the values with references
to values and the same observations apply.
duke
2012-05-31 23:07:24 UTC
Permalink
On Thursday, May 31, 2012 2:38:41 PM UTC-6, Jeffrey Scofield wrote:

[snip]
Post by Jeffrey Scofield
let val x = 3 in let val x = 4.0 in ... end end
That line of code I understand!
Post by Jeffrey Scofield
There are two different things named x. One has the value 3, the other
has the value 4.0. In the innermost scope (...), the outer x isn't accessible
by name, due to the shadowing.
^^^^^^^^^^^^^^^^^^^^

This is the part that confuses me! What is meant by this "shadowing"?? We have 2 scopes, each with a binding using the same label. OK. The innermost can't see the outer. Fine!

When the inner "block" is done, x= 4.0 disappears, and outer x = 3 is visible. OK. So where does "shadowing" enter into all of this?
Jeffrey Scofield
2012-06-01 03:37:03 UTC
Permalink
When the inner "block" is done, x= 4.0 disappears, and outer x = 3 is
visible. OK. So where does "shadowing" enter into all of this?
I'd say you get it then. The word "shadowing" is just a metaphor; it
doesn't add anything new to the idea. It's just saying that the
outer binding is in the shadow of the inner binding for a while. I
guess it's kind of like a solar eclipse (metaphorically). The inner binding
temporarily blots out the outer one, but when the inner
binding moves away, the outer one is still there like it was before.

Regards,

Jeffrey
duke
2012-06-01 03:59:31 UTC
Permalink
When the inner "block" is done, x= 4.0 disappears, and outer x = 3 is
visible. OK. So where does "shadowing" enter into all of this?
I'd say you get it then.  The word "shadowing" is just a metaphor; it
doesn't add anything new to the idea.  It's just saying that the
outer binding is in the shadow of the inner binding for a while.  I
guess it's kind of like a solar eclipse (metaphorically).  The inner binding
temporarily blots out the outer one, but when the inner
binding moves away, the outer one is still there like it was before.
LOL ... and shortly after I posted my last reply, I found the
following on an Erlang site:

[quote]If you try to compile it, you'll get a warning about shadowing
("Warning: variable 'A' shadowed in 'fun'"). Shadowing is the term
used to describe the act of defining a new variable that has the same
name as one that was in the parent scope. This is there to prevent
some mistakes (usually rightly so), so you might want to consider
renaming your variables in these circumstances.[/quote]

I was thinking that it it was a special compiler operation or FP
slight-of-hand, or some such ... :?

Thanks for clearing that up!
NatarovVI
2012-06-09 11:06:01 UTC
Permalink
Post by duke
I realize that in FP "bindings" are more like constants in other
languages. They're supposed to be immutable. So can you explain to me
what this "shadowing" is in terms of the above Oberon example? It seems
that I'm getting bogged down in the semantics of SML et al.
you just can think about _sequential_ definitions in ml as
about _enclosing_ definitions in oberon, scoping more and more in deep,
and without return to upper levels. next level based on all previous, and
shadows it, but invisible from it. in functional language

:x=1;
::y=x+1;
:::x=y+1;
::::y=x+1;
...

is more like

begin
:x=1;
:begin
::y=x+1;
::begin
:::x=y+1;
:::begin
::::y=x+1;
...

see? all definitions is _immutable_, it's only added and never deleted.
such immutability looks strange and inefficient at first glance.
but permits parallelisation!
George Neuner
2012-06-02 21:28:02 UTC
Permalink
Post by Florian Weimer
Post by duke
Is this "shadowing" ambiguity (or "trip-wire" :D ) an SML-only
issue, or is this prevalent in FP languages in general?
Most languages with lexical scoping share the shadowing aspect.
What's different in SML is that the right hand side of a binding can
use the same name, refering to an earlier name. This applies to value
structure S = MkS ()
structure S = Transform (S)
val v = mkValue ()
val v = transform v
This particular aspect of shadowing (and actual use in programming
styles) is pretty much restricted to SML and very close derivatives
(and for good reasons, IMHO).
Hardly. ML has roots in Lisp where references to shadowed bindings
not only are permitted, but are necessary for correct implementation
of Lisp's "special" global variables.

Like ML, Scheme has no equivalent of Lisp's special variables, yet it
too permits references to shadowed bindings.

George
Florian Weimer
2012-06-10 19:15:42 UTC
Permalink
Post by George Neuner
Post by Florian Weimer
This particular aspect of shadowing (and actual use in programming
styles) is pretty much restricted to SML and very close derivatives
(and for good reasons, IMHO).
Hardly. ML has roots in Lisp where references to shadowed bindings
not only are permitted, but are necessary for correct implementation
of Lisp's "special" global variables.
It's also in Lua and Perl. So perhaps the Ada/C/C++/Java/Python
behavior is the outlier here.
George Neuner
2012-06-11 17:12:24 UTC
Permalink
Post by Florian Weimer
Post by George Neuner
Post by Florian Weimer
This particular aspect of shadowing (and actual use in programming
styles) is pretty much restricted to SML and very close derivatives
(and for good reasons, IMHO).
Hardly. ML has roots in Lisp where references to shadowed bindings
not only are permitted, but are necessary for correct implementation
of Lisp's "special" global variables.
It's also in Lua and Perl. So perhaps the Ada/C/C++/Java/Python
behavior is the outlier here.
Technically no - underneath they all work similarly. What's different
about the FP languages really is the focus on convenient syntax.
Recall that in Lisp:

(let ((a b)) ... ) <--> ((lambda (a) ... ) b)

Although generally not implemented in this way, LET can be considered
to be an implicit function call. (LET ((a a)) ... ) is the moral
equivalent of passing the current binding of 'a' as an argument to an
anonymous function which has a formal parameter also named 'a'.

ML works similarly, but its assignment-like binding syntax hides the
fact that a new lexical scope has been opened.

When lexical binding is viewed as a function call, it becomes obvious
that it is (briefly) possible for bindings having the same name in
different scopes to be visible simultaneously ... in any of the
aforementioned languages.


The behavior of Lisp's "special" variables is a little harder to
grasp. A special variable is a global binding which refers to a
hidden logical stack of values. The lifetime of a value on the stack
follows lexical scoping, but its visibility when on the top of the
stack is global (or at least thread-global).

ex:
(defvar *A* 'hello) ; creates special variable *A*

(defun printit ()
(print *A*))

(defun main ()
(printit)
(let ((*A* 'bye))
(printit))
(printit))

(main)
=> HELLO
BYE
HELLO

The LET in function "main" changes the value of *A* for the duration
of its scope, but the original value of *A* is restored when the scope
exits. (LET ((*A* *A*)) ... ) pushes a new value onto the binding
stack which is a copy of the previous value.

George
duke
2012-05-30 13:21:37 UTC
Permalink
Thanks everybody!!

In truth, the more I look into FP languages, the more I appreciate Wirth's use of Einstein's one-liner, "Make it as simple as possible, but not simpler", in reference to his Oberon language.
NatarovVI
2012-06-09 10:41:05 UTC
Permalink
Post by duke
In truth, the more I look into FP languages, the more I appreciate
Wirth's use of Einstein's one-liner, "Make it as simple as possible, but
not simpler", in reference to his Oberon language.
and this epigraph sticks only to Oberon-1, not Oberon-2 or Component Pascal...
in past times... i also likes such filosofy, likes Oberon.
but now understand:

1) Oberon do not define libraries, and their complexity way bigger
than language complexity. it's small project for specific purpose. and
makes specific solutions, solutions only for that purposes, not generally
applicable.

2) Oberon language is minimum-minimorum, procedural-only sequential
core. it's for system programming, not for applications.
It don't have lists or other frequiently used in applications data
strictures and send user to libraries for such functionality. meanwhile, like Ada.
SML has lists.

3) Oberon not defines parallel semantic, it mere ephemeral/procedural.
I know about Bluebottle, and procedural programming in it remains be hard.
Functional, immutable, languages simplify parallel programming. Yes,
such languages is more complex. Because task of parallelisation is.

4) Oberon do not permit to have two independently developed
applications coexist. Oberon just do not thinks about interoperability,
like Ada 83. All oberon system must be one, extensible, application.
All modules have only one "true" implementation.
By design, one version for all.
This gives coherency and small total size, but deny independent
development of applications because module namespace is common and
shared for all developers for all applications.
"One oberon system - one application".
In SML signatures:structures is many-to-many relation, and has not
reliability problems like multiple inheritance, because not transitive.

and etc and etc...

Oberon is good, but you can not directly compare it with other languages,
with general-purpose languages, like SML. They have different semantic
and different powers, they have different purposes and different solutions,
different functionality.
SML can be simplified, i think, but it is not so complicated ever.
Haskell is overcomplicated, maybe Ocaml. not SML. SML is small against Ocaml
or Haskell...
duke
2012-06-09 13:08:40 UTC
Permalink
Post by NatarovVI
Post by duke
In truth, the more I look into FP languages, the more I appreciate
Wirth's use of Einstein's one-liner, "Make it as simple as possible, but
not simpler", in reference to his Oberon language.
[snip]
Post by NatarovVI
Oberon is good, but you can not directly compare it with other languages,
with general-purpose languages, like SML. They have different semantic
and different powers, they have different purposes and different solutions,
different functionality.
SML can be simplified, i think, but it is not so complicated ever.
Haskell is overcomplicated, maybe Ocaml. not SML. SML is small against Ocaml
or Haskell...
I agree! It seems that Oberon was NOT designed with parallel programming in mind! :) However, it WAS used to build an entire OS _and_ ALL the applications that ship with it. So, IMHO, it is a "general-purpose language", that is STILL going begging for people to write extension modules for it - so that it can become even more "general-purpose" :)

I agree that SML seems "lighter" and more easily digestible that some other FPLs.
Richard
2012-06-09 14:15:00 UTC
Permalink
(added comp.lang.oberon to the newsgroup list)
Post by NatarovVI
Post by duke
In truth, the more I look into FP languages, the more I appreciate
Wirth's use of Einstein's one-liner, "Make it as simple as possible, but
not simpler", in reference to his Oberon language.
in past times... i also likes such filosofy, likes Oberon.
The rating "as simple as possible" always depends on the goals one
wants to achive. The Oberon programming language was designed to
implement the Oberon System and its application programs.

Nevertheless, it is a general-purpose programming language and
contains features like local procedures which are not available in
many other programming languages and would not really have been
necessary to implement the Oberon System.
Post by NatarovVI
1) Oberon do not define libraries, and their complexity way bigger
than language complexity. it's small project for specific purpose. and
makes specific solutions, solutions only for that purposes, not generally
applicable.
A lot of libraries (modules) are targeted to the Oberon System and its
unique user interface. If you want to create native user interfaces
for other operating systems, you have to use different libraries. This
is the same for all programming languages.
Post by NatarovVI
2) Oberon language is minimum-minimorum, procedural-only sequential
core. it's for system programming, not for applications.
I do not agree with this assertion. Applications can and have been
created with Oberon and other "procedural-only sequential" programming
lanuguages.

Also, Oberon supports type extension and thus reuse and extensibility
similar to object-oriented languages. Therefore, I would not call it a
"procedural-only" programming language.
Post by NatarovVI
It don't have lists or other frequiently used in applications data
strictures and send user to libraries for such functionality. meanwhile, like Ada.
SML has lists.
Oberon is similar to Java before version 1.5 in this respect: It is
possible to create and use collection libraries, however, due to the
lack of generics, it is often preferable to use built-in arrays or
pointers resp. references explicitly.
Post by NatarovVI
3) Oberon not defines parallel semantic, it mere ephemeral/procedural.
Similar to many other programming languages there is no explicit
support for parallelism. This does not preclude parallelism supported
by libraries and operating systems.
Post by NatarovVI
4) Oberon do not permit to have two independently developed
applications coexist. Oberon just do not thinks about interoperability,
like Ada 83. All oberon system must be one, extensible, application.
All modules have only one "true" implementation.
By design, one version for all.
These are concepts of the Oberon System. When using the Oberon
language on other operating systems, it is easily possible to link
different versions of a module to a program or library.
Post by NatarovVI
Oberon is good, but you can not directly compare it with other languages,
with general-purpose languages, like SML. They have different semantic
and different powers, they have different purposes and different solutions,
different functionality.
The Oberon language is a general-purpose programming language
comparable to languages like Java. The Oberon System and it's
libraries are, however, quite different from everything else.

Richard
Владислав Натаров
2012-06-10 04:11:53 UTC
Permalink
to achive. The Oberon programming language was designed to implement the
Oberon System and its application programs.
exactly. and only for that target.
Post by NatarovVI
2) Oberon language is minimum-minimorum, procedural-only sequential
core. it's for system programming, not for applications.
I do not agree with this assertion. Applications can and have been
created with Oberon and other "procedural-only sequential" programming
lanuguages.
sure applications _can_ be created with systems programming language
like C
or Oberon or even assembler. it just only somewhere harder because
language is not
for that, because language works with lower level of abstractions.

but application development can be done _easier_ if language directly
supports
frequiently used data structures, for example, and with simple
readable uncluttered syntax.

...about question of making _portable_(running on any processor with
any
available number of cores without modifications) parallel applications
(not OSes!)...
multicore is mainline now. and _portable_ parallelism is just harder
in Oberon or
any other procedural language, than in SML. All that concurrency,
threads, locks is dpendent on number of cores and on width of memory
buses...
madness! errorprone! And... is just not necessary in 90% of
applications!
Deterministic parallelism will be sufficient.
For that we need higher level of language abstractions (for automatic
parallelising program transformations "map-reduce" is way better than
"if"
and "while"), we need immutability-by-default and strict-by-default
(meanwhile,
lazy-by-default makes parallelisation _harder_). We need strong static
typing.
list of such languages is not big.

look at existentialtype.wordpress.com, Robert Harper say some VERY
simple
arguments about teaching parallel programming to first-course newbies.
I even spend month of my time to translate his truths to my sarcastic
russian...

agin. this is not question of "can". this is more like "how easy".
and such thing is named "progress of technologies"))
yes, SML is more complex... but... we can't live without such features
as RH clearly shows.
Also, Oberon supports type extension and thus reuse and extensibility
similar to object-oriented languages. Therefore, I would not call it a
"procedural-only" programming language.
hmm... i really do not understand wich "reuse" OOP adepts mean in
his blind stupid prairy enchantations about "superiority" of OOP.
this is definetely not reuse, reuse must not ever be "reuse-all"
because
that "all" is continuously changed in real world.
reliable reuse must be "reuse separately specified functionality,
verbose list of that functionality is attached".

modules, with separate interface and implementation parts, gives such
good, real, reuse. but inheritance purposely broke
modularity("incapsulation"),
tightly glues parts and so broke reuse in oop.
inheritance is more like "technology of patches",
transforming solid replaceable (because independent!) modules to
uncontrollable intertwined heap of ropes. Inheritance is really,
really BAD
idea in our "stupid programmer's, managers, users" world.
_internal_ structure of module is showed on the level of modules?
oh-o, thats bad! but this is theme for other separate long news
thread...
and i not want to explain lenghty program reliability and
modication problems here.

so... what with that Oberon type extension? i think Wirth just try to
experiment
with inheritance. And inheritance was included not because it
_needed_, Wirth
wants just to try it and see how it works. Plus all that OOP hype of
that time.
He just wants to build some new coherent "system of axioms" with this
axiom.
This was just good experiment, no more. Yes, he builds some GUI
system.
So what? why you conclude that such system is "one true paradigm for
all"?
He just want build GUI for workstation, no more. OOP is good for GUIs.
Because buttons always will be buttons...
meanwhile, followers of Wirth (like Michael Franz)
understands problems with inheritance... and their recommendations
just looks like they try to build old modular interface-implementation
relation
with ropes of inheritance... like pushing nail with screwdrivers.
Oberon is similar to Java before version 1.5 in this respect: It is
possible to create and use collection libraries, however, due to the
lack of generics, it is often preferable to use built-in arrays or
pointers resp. references explicitly.
SML have polymorphism and functors...
...but real brick on way of procedural languages to future is not
generics.
generics only shortens programs, at the end of words...

real stop is inability to automagically achieve portable and easy
deterministic
parallelism.
too many interdependencies in code, making it almost impossible to
automatically
transform program for current multiprocessor.
functional language is _required_ for parallel era.
let alone mere data-parallelism, we need more general mechanic,
and easily used, deterministic mechanic. not threads or other low-
level
concurrency madness. more like Sisal, Nesl.. that way.
current slogan is "get 90% of available parallelism almost for free",
that's the way. threads is like parallel goto. too many errors.
Similar to many other programming languages there is no explicit support
for parallelism. This does not preclude parallelism supported by
libraries and operating systems.
and that other languages also will die in future years as i think.

about libraries... they must be designed such so to be not only
general,
efficient but also bulletproof in use. on language level checking of
contracts is done simpler. by typesystem.
These are concepts of the Oberon System. When using the Oberon language
on other operating systems, it is easily possible to link different
versions of a module to a program or library.
Yes, by purposely maked OS ways, not Oberon ways. as as say, Oberon
system and it's garbage collector and module loader is thing-in-
itself,
closed world. And because of _that_ it simple.
The Oberon language is a general-purpose programming language comparable
to languages like Java. The Oberon System and it's libraries are,
however, quite different from everything else.
"general-purpose" is so undefinite word...
assembler is also general-purpose (MenuetOS).
maybe we must just say some like "turing-complete"? hehe))

...as i sayed, question is not "can be used" but "how easy".
many modern languages is NOT easy or reliable or even good at
development
of sequential apps. let alone parallel....
it's just used because of management.
Oberon is good, in sequential case, but don't have management
backings.
And it don't make future parallel programming easier, and because of
that
remains in history. Rest in peace, unknown hero Oberon.
Richard
2012-06-10 13:53:59 UTC
Permalink
Post by Владислав Натаров
but application development can be done _easier_ if language directly
supports
frequiently used data structures, for example, and with simple
readable uncluttered syntax.
I have found the ability to organize application programs based on
type hierarchies to be more important than having concise syntax for
data structures.
Post by Владислав Натаров
so... what with that Oberon type extension? i think Wirth just try to
experiment
with inheritance. And inheritance was included not because it
_needed_, Wirth
wants just to try it and see how it works. Plus all that OOP hype of
that time.
Wirth needed a type-safe way to build an extensible system. So he
included type extension in the language. He did not include other
object-oriented features like methods and multiple inheritance. So, no
experiments there.
Post by Владислав Натаров
Similar to many other programming languages there is no explicit support
for parallelism. This does not preclude parallelism supported by
libraries and operating systems.
and that other languages also will die in future years as i think.
On the other hand, as Jonathan Edwards (alarmingdevelopment.org) put
it, CPU cycles are a lot less important than programmer cycles.

People will probably not leave their favorite programming languages
just to help compilers perform optimizations which are not needed in
most cases anyway.

Richard
Владислав Натаров
2012-06-11 01:09:40 UTC
Permalink
Post by Richard
I have found the ability to organize application programs based on
type hierarchies to be more important than having concise syntax for
data structures.
i just want to say that having simple lists etc. in language is good.

...hierarchy? it shows our understanding of task. there is nothing
bad with OOP-ish hierarchies... but only until our task or our
understandings not changed))
if such situation is possible then doing flat modularity
from start is better.
OOP hierarchies is hard to modify, just it.
All knows it, but many programmers continue to achieve
his "true, final, universal, solutions" and until now thinks
that "adding more code is always better".
Do not patch legacy, peoples! Just throw to archive and replace...
Post by Richard
Wirth needed a type-safe way to build an extensible system. So he
included type extension in the language. He did not include other
object-oriented features like methods and multiple inheritance. So, no
experiments there.
old modula-2 variant records also gives extensibility...
SML has extensibility without OOP...
...there is many other typesafe ways for polymorphism
and extensibility.

i say, there is nothing "inherent truths" in Wirth solutions,
just good, artistic, ingeneering expression of one of possible styles.

meanwhile, inheritance imho is NOT type-safe "in time", safe only in
one moment. exactly, it do not _saves_ type-safety after code
modufications. contracts not checked because detailed contracts
just not exist.
Post by Richard
Post by Владислав Натаров
and that other languages also will die in future years as i think.
On the other hand, as Jonathan Edwards (alarmingdevelopment.org) put
it, CPU cycles are a lot less important than programmer cycles.
yes, maybe. parallelism is just optimisation for efficiency.
correctness and quality of program is imho more important.
hmm, i may also rephrase JE saying: programmers is too greedy now))

on the other side, performance difference or latency reduction in N
times is hard to miss by user. this is concurent advantage and will
be used by leaders sooner or later. is they want to be leaders.

and more thoroughly thinked, more abstract project in FP style is
usually more correct also, has less bugs. by design.
Post by Richard
People will probably not leave their favorite programming languages
yes, mind lasiness is inherent for peoples.
Chris Burrows
2012-06-11 06:32:41 UTC
Permalink
Post by Владислав Натаров
Post by Richard
Wirth needed a type-safe way to build an extensible system. So he
included type extension in the language. He did not include other
object-oriented features like methods and multiple inheritance. So, no
experiments there.
old modula-2 variant records also gives extensibility...
Yes, but ...

Variant records in Modula-2 are NOT type-safe. They are plagued with the
same problems as variant records in Pascal:

"An undisputed candidate for elimination was Modula's variant record.
Introduced with the laudable intent of providing flexibility in data
structuring, it ended up mostly being misused to breach the typing concept.
The feature allows to interpret a data record in various ways according to
various overlaid field templates, where one of them is marked as valid by
the current value of a tag field. The true sin was that this tag could be
omitted."

Ref: Modula-2 and Oberon> Niklaus Wirth, Paper submitted to HOPL-3, June
2005

"Variant records are eliminated, because they constitute a genuine
difficulty for the implementation of a reliable storage management system
based on automatic garbage collection. The functionality of variant records
is preserved by the introduction of extensible data types."

Ref: From Modula to Oberon, N.Wirth 1.10.1990

Regards,
Chris Burrows

CFB Software
http://www.cfbsoftware.com
Владислав Натаров
2012-06-12 03:14:43 UTC
Permalink
Post by Chris Burrows
Post by Владислав Натаров
old modula-2 variant records also gives extensibility...
Yes, but ...
Variant records in Modula-2 are NOT type-safe. They are plagued with the
"... marked as valid by the current value of a tag field. The true sin was
that this tag could be omitted."
"Variant records are eliminated, because they constitute a genuine
difficulty for the implementation of a reliable storage management
system based on automatic garbage collection. The functionality of
variant records is preserved by the introduction of extensible data
types."
hmmm... i remember, i read this words some years earlier))
looks like that will be long talk. let's begin...
imho, tagged record potentially _is_ typesafe, maybe just it
implementation in modula-2 is not? or automatic conversion of
base types do it's dirty work transforming tags or just
work with tags is not enough hidden from programmer?
hmm... yes, i think that working with tag was just not
enough hidden and automatic, like in SML.

and i do not remember if modula-2 compiler do exaustiveness checks
that is, check that programmer defines processing for all possible
type
kinds of variant record. i definetely can say that is SML this
mechanic,
pattern matching plus exaustiveness check in function definitions,
is typesafe and checked. maybe type inference or higher level of
that language helps?
what i want to say... definetely there _is_ other ways beside
inheritance, typesafe ways. without inheritance drawbacks.

...meanwhile, maybe Wirth say more about bad programmers,
not about bad variant records))
maybe programmers just try to misuse variants, try to store
in it different types, not different kinds of one type?
and because type system of modula (which is system's
programming language) is too permissive they can?
there is simple article at existentialtype.wordpress.com about
variants.
named "dynamic languages are static languages".

now about garbage collection. Wirth just selects way which he
think will be easier for him. but, imho, he just delay deploying
of full solution )) what i mean? the more i think, the more i
understand that inheritance is very like pointer, just on a bigger
time scale. pointer exist at runtime, inheritance exist at lifetime
of program.
meanwhile, goto, pointers, inheritance, threads, imperativeness,
ephemeral data structures... all that things look like each other,
and gives very similar problems to programmer. and i found why:
because that things based on principle of "one-way" dependence.
such dependencies permit changes flow only in one way, not back.
having that, with time we loose program consistency.
you see how simple? ALL problems of IT traced to loosing of
consistency (contracts) because one-way dependencies used.

...with the relational two-way dependencies such problem not exist
and consistency can be maintained automatically.
so, solutions to all IT problems are similar: goto and threads packed
in more safe and self-sufficient higher-level structures, pointers
packed
with garbage collector for restoring it consistency (or maked two-way
with ring of backpointers), ephemeral data structures and procedural
programming replaced by immutable data structires and parallel
functional programming etc...
... maybe i write article on all that sometime...

so... if you read me carefully, you already understand what Wirth
do. he pushes garbage collection implementation problems with
variants from runtime - to problems with inheritance at program
lifetime. and left to programmers restoring of consistency,
periodically broken by inheritance, manually...
problem still exist, it just harder to see now, because they
at bigger timescale. and we looks only at our hands, not around,
as usual)). he not solve problem, he just hide it from casual
observation.

to be fully complete (if he not want implement garbage collector,
correctly working with variants... hmmm seems that was hard
mainly because language is targeted as system's language,
because language is too low level) his solution must include
some "lifetime garbage collector" for programs, tracing and
showing problems with changes in inheritance hierarchy
to programmer.
Wirth solutions - is good solutions for _his_ problems, not
for _all_ problems. And _that is good_

NatarovVI
2012-06-09 09:54:31 UTC
Permalink
Post by duke
Am I to understand that the _point_ to the above is that a _new_
variable is created, albeit with the same name, and that the old
variable (with the same name) is discarded? That, there is no re-
assignment going on, just a "nuke and bind" operation? Am I close?
new value created and begins accesible having old name. old value
is not accessible anymore in next definitions, but remains accesible
in old definitions. so you now have TWO values, and only new of it
have name. old value still exist but now anonymous.
until garbage collected.

such method (create new, not modify old) is good for parallelism,
when value can be accessible from many processes.
Loading...