[Info-vax] BASIC (was Re: 64-bit)

Dan Cross cross at spitfire.i.gajendra.net
Sat Jan 13 09:53:09 EST 2024


In article <uns4vp$3iumi$1 at dont-email.me>,
Dave Froble  <davef at tsoft-inc.com> wrote:
>[snip]
>Overall, your post is interesting.

Thanks!

>On 1/12/2024 12:26 PM, Dan Cross wrote:
>> In article <unqjcn$3c1o2$1 at dont-email.me>,
>> Dave Froble  <davef at tsoft-inc.com> wrote:
>>> On 1/11/2024 2:42 PM, Dan Cross wrote:
>>> [snip]
>>> Which then asks the question, are such really better?  Perhaps some of that is
>>> more opinion than fact.
>>
>> Some of it is opinion.  Some of it is limitations in the
>> language.  Some of it is suitability for purpose.
>
>Suitability for purpose is always rather important.

Indeed, which in turn raises the question again: why is VSI
BASIC more suitable for a particular task, even in the domain of
business data processing, than another newer language?

If I were to start writing something from scratch today, given
some modest requirements ("the data is in an SQL database; you
need a web-based frontend") why would I choose BASIC for VMS
over, say, Python or Java or one of the JVM languages, which all
also run on VMS?

>>> Below, when I write Basic, I'm referring to DEC/Compaq/HP/VSI Basic.
>>
>> Understood.
>>
>>>> VSI BASIC appears to have a few useful things like static type
>>>> definitions, functions, etc, and it frees the programmer from
>>>> _having_ to specify e.g. line numbers.  But it doesn't seem to
>>>> have a lot of support for other abstraction facilities like
>>>> modules, classes, or anything of that nature.
>>>
>>> What amuses me about that is that when people talk about "classes", I don't have
>>> a clue what they are talking about.  Perhaps I do, if the case is new names for
>>> old concepts.  That is something I didn't like about Microsoft, they seemed to
>>> like re-naming concepts.
>>
>> I'm not sure what Microsoft has to do with it.  The concept of a
>> "class" has existed in one form or the others since Simula in
>> 1967.
>>
>>>> String handling
>>>> seems anemic.
>>>
>>> Can't let that one go.  Basic in my opinion does strings very well.
>>
>> What do you like about it?
>>
>> Consider writing a lexical analyzer for a simple expression
>> language; what would such a thing look like, in BASIC?  Here I
>> want to take a string as input, and emit a list of tokens that
>> correspond to the elements of the langauge that are represented
>> in that string.
>
>Don't totally understand, perhaps parsing for commands, switches, and such would 
>be similar.

Given a string such as, "(a + b)*0.6/365" and a taxonomy of
token types such as LPAREN, RPAREN, IDENTIFIER, PLUS, REAL, INT,
STAR, SLASH, etc, convert the above string into a list of tokens
giving [LPAREN, IDENTIFIER("a"), PLUS, IDENTIFIER("b"), STAR,
REAL(0.6), SLASH, INT(365)].

Here's an example of a Token definition in SML:

datatype Token =
    LParen
  | RParen
  | Star
  | Slash
  | Plus
  | Minus
  | Identifier of string
  | Real of real
  | Int of int

Given such a type definition, you could build a scanner for that
little language in, oh, I dunno, 50-100 lines or so.

>>>> There doesn't seem to be support for generalized
>>>> memory pointers,
>
>A pointer data type can be very useful.  A compiler could use such to generate 
>proper sizing for different systems.  But, in the end, it is just a numeric 
>piece of data.  If one can process the numbers, that works.  Not as generic, 
>but, it works.  For VAX, it is an unsigned longword.  For 64 bit addressing, it 
>is an unsigned 64 bit integer.

The thing is that a 64-bit integer inheritly carries no type or
validity information when used as a pointer.  You can add 5 to
it and dereference it; is that valid and meaningful?  Who knows?
The point is that with languages that make references first
class objects, you may get much stronger guarantees: by
definition the reference points to a valid object of the given
type.  Outside of shenanigans designed to fool the language, it
can never be nil, nor can it ever point to an object of a
different type.  If we strengthen the presupposition to the use
of a type- and memory- safe language (such as Ada, Go, Rust, ML
and so on) then we can guarantee there are no dangling
references either.

>For example, what is the difference between memory pointers and indices in an in 
>memory resident data  structure, such as linked lists?  Not much, in concept, right?

In implementation not so much: after all, as you point out these
are just numerical data.  But conceptually, quite a bit, I'm
afraid.  An index is tied to a particular collection, like an
array; a given integer treated as an index may refer to many
different objects depending on what array it is applied to.
Indeed, every non-empty array has a first element, so 0 or 1
(depending on the language) is valid in a whole bunch of things.
References, on the other hand, by and large exist with a single
namespace (the address space enjoyed by the program).  Of course
there are some exceptions to that, particularly when we start
messing around with virtual memory, but to a first order
approximation it's reasonably accurate.

But unlike a reference, an index may not be valid; suppose one
extends beyond the end of the underlying storage object; it may
refer to something completely invalid.  Can indices be used to
build linked lists or binary trees or other similar structures?
Yes, but not safely.

>>> Correct, Basic does not have any pointer data types.  It does have a function to
>>> retrieve the value of a pointer.
>>
>> That makes it challenging to implement dynamically sized data
>> structures like trees or graphs where the size is not already
>> known, or hash tables that use chaining for collision resolution
>> etc.
>
>Not really.  There is always LIB$GET_VM.

Note I said challenging; not impossible.  :-)

>> How would I do these things in VSI BASIC?
>
>Once you can get the memory, what's the difference between say, linked lists 
>there, vs using pre-allocated array(s)?

Convenience and safety, more than anything.  Perhaps one doesn't
care, but then what's the difference between using BASIC and
Macro-32?

>>>> let along non-nullable references, so your
>>>> ability to create rich linked data structures seems limited.
>>>
>>> Not sure what that means ...
>>
>> Basically, pointers that are always valid in pointing to an
>> object of a known type and and that can never be nil.
>
>Seems to me, pointers/indices in use always have a valid value?

Sadly no; years of experience have shown us that programmers
make mistakes that invalidate their assumptions about the
validity of memory objects all the time.

>>>>  I
>>>> don't see any support for higher-order functions,
>>>
>>> Not sure what that means ...
>>
>> Basically, functions that can be passed as arguments to other
>> functions or functions that can be returned from functions.
>> These let me do things like write a generic hash table
>> implementation, where I can then parameterize calls into the
>> resulting data type with functions that implement the actual
>> hash for particular types of data.  "Hash table of FOO."
>
>Hash tables takes me back to the mid 1970s.  :-)
>
>Is what you mean something like:
>
>Z = FIX( SQR( SomeValue ) )
>
>Yeah, rather simple, but is that what you refer to?

No?  I mean, I suppose someone could use something like that as
a (not very great) hash _function_, but that then you've got to
build up a whole structure around that.

>>>> lambdas,
>>>
>>> Not sure what that means ...
>>
>> Anonymous functions; ie, functions that are unnamed.  They're
>> very handy in languages that support higher-order functions.
>> For example, I can trivially write a projection function that
>> will extract a particular member from a data structure to use
>> as a sort key.
>
>Not sure if you're making my brain hurt, or discussing something so simple it 
>doesn't deserve a name.  I've built sort keys for longer than I can remember.

Well, my SML code had some examples.

>>>> or
>>>> closures;
>>>
>>> Not sure what that means ...
>>
>> Functions that are created dynamically and "close over" part of
>> their surrounding environment, e.g., to capture a value that is
>> used in the closure itself.
>
>More brain pain ...

Sorry!

>>>> no currying of functions.
>>>
>>> Not sure what that means ...
>>
>> Partial application of a function, which allows me to create a
>> new function that calls some underlying function with some
>> arguments already "filled in".  An example, from SML:
>>
>> fun fib' a b 0 = a
>>   | fib' a b n = fib' (a + b) a (n - 1)
>>
>> val fib = fib' 0 1
>>
>> Here `fib` is a function to return the nth Fibonacci
>> number.
>
>Why does that require a special name?

Partial function application?  It's named after Haskell Curry,
who was a mathematician and logician who studied functions (as
in the mathematical notion).

>> This example demonstrates several of these concepts:
>>
>> ; sml
>> Standard ML of New Jersey (64-bit) v110.99.4 [built: Tue Aug 01 16:07:38 2023]
>> -  val fib =
>> =      let fun fib' a b 0 = a
>> =            | fib' a b n = fib' (a + b) a (n - 1)
>> =      in  fn n => fib' 0 1 n
>> =      end;
>> val fib = fn : int -> int
>> - fib;
>> val it = fn : int -> int
>> - fib';
>> stdIn:3.1-3.5 Error: unbound variable or constructor: fib'
>> - map;
>> val it = fn : ('a -> 'b) -> 'a list -> 'b list
>> - map (fn n => fib n) [1,2,3,4,5,6,7,8,9];
>> val it = [1,1,2,3,5,8,13,21,34] : int list
>> - ^D
>> ;
>>
>> Here, we see an example of a closure, in which the anonymous
>> function (aka, lambda) returned from the `let` clause that is
>> bound to `fib` closes over the `fib'` function, which is not
>> visible outside of the `let`.  Furthermore, `fib` is an example
>> of currying as above.  We see the use of higher-order functions
>> in the call to `map`, which applies `fib` to each element of the
>> given list.  We can see it again with a slightly different
>> example:
>>
>> - List.tabulate(10, fn n => fib n);
>> [autoloading]
>> [library $SMLNJ-BASIS/basis.cm is stable]
>> [library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
>> [autoloading done]
>> val it = [0,1,1,2,3,5,8,13,21,34] : int list
>>
>> Again, these are all examples from Standard ML, a langauge that
>> dates from the 80s, and takes its roots in the 70s.
>
>I'm going to guess that your experience includes labels for certain things, 
>which might be helpful at times, and exist in subsets of programming practices. 
>Nothing wrong with that, but might be confusing to some others.

These are pretty standard names.  The `List.tabulate(10, fib)`
example just shows the power of a few simple ideas.

>>>>  Statement modifiers seem
>>>> kind of neat, but I bet they can be easily misused.
>>>
>>> Statement modifiers are very useful, and in some ways make code easier to
>>> understand.
>>
>> I'm sure they are useful, but I can also imagine that they can
>> turn into spaghetti if not used judiciously.
>>
>>     X = X * 0.1 unless FOO != 2;
>>     X = X * 0.2 unless FOO = 2;
>>
>> seems strictly less readable than
>>
>>     IF FOO != 2
>>         X = X * 0.1
>>     ELSE
>>         X = X * 0.2
>>
>> (Apologies for syntax errors.)
>
>The first thing any programmer should learn is, at some time in the future code 
>will be read by another, and if it is not concise, clear, and understandable, it 
>is the fault of the original programmer, and he/she should find another occupation.

And yet we have billions of lines of impenetrable code that show
that this is not universally true.  Sadly.

>Yes, if-then-else, select case, and such can be good, and I've also seen such be 
>hundreds of lines of code, and a real PITA.  I tend to favor modular code. 
>Simple, short, and to the point.

Agreed, but the question is whether the language provides
features that facilitate that, or that can be easily abused?
Most non-joke languages try to make it relatively hard to abuse,
but some are more successful than others.

Further, a focus on this line of discussion has been on whether
the language provides good facilities to modularize code; being
able to limit visibility of functions and data and so on.  I
don't see that BASIC does very much in this domain.

>But for a simple true or false, the statement modifiers can be very useful.  In 
>your first example, FOO should be evaluated only once.

Sure; my point is that they can also be abused.

The 32-bit ARM instruction set has modifiers that make execution
of some instructions conditional on bits in the PSW; while kind
of cool, they can also lead to some really thorny code that is
difficult to understand.

>>>> All in all, it doesn't look like a terrible language (it's not
>>>> COBOL); it looks like an early-1980s-era language.  But nothing
>>>> about it jumps out at me as being spectacularly amazing, either.
>>>
>>> It's not amazing, it just works.
>>
>> Sure.  That doesn't mean that it's good by modern standards.
>
>Nor does it mean it is bad either.

True.  But given a choice between two languages, all else being
equal, would I chose the "meh it's fine" language or the one I
felt was better designed?

	- Dan C.




More information about the Info-vax mailing list