2.23: adda/cstr/set generator:
(^ x,y,z: int . f(x,y,z) ) -- this is the set generator;
see how the power param is terminated by a period?
the reason that can't be the usual math operators {: | }
is due to (:) being confused with the label declaration
and with other math uses for (| ) .
. (x.t, y.t) can also be defined by ( x,y: t ).
2.29:
. even if it was ok to overload (| ),
the form of it is opposite of what I need:
math puts the control var to the right of (|):
{ f(x) | x in t }
when I want the control var as the head:
{^ x in t .
f(x)
} -- that way var's are declared before they are used,
and it's easier to read generally,
when the body of the generator is getting large
(I have to admit that for math's one-liner's,
the math way looks neater ).
2012-02-29
multi-inheritance
2.20: adda/oop/multi-inheritance:
. the essence of what a call to the supertype does
is manage its own ivars (instance vars)
during alloc, init, dealloc;
so, when you multi-inherit, then your call to super is
sent to each parent class .
. self`super(function)
-- this would be a good syntax because
it shows the self is being modified by a super function
which takes as arg, self and a function to send to supers .
. so how does each supertype in a multi-inheritance
know where its ivars are within the given obj?
. the first part of the object
has to be a dictionary of classes that
tells each super where their ivars are located .
. in the most general form of oop operation
there are 2 type tags:
# which type among all unrelated types:
(eg, is it a character string or a number?);
# within a type, which subtype it is:
(eg, is the number an integer, float, or quotient?).
supertype.tags can be implicit:
. we can save space in a var's storage
by ensuring that it's always assigned
values of a particular type
so that the type tag is no longer needed
because the owning subprogram's symbol table
already has it .
. if, according to the symbol table,
this object is typed,
then we can expect that
only that type has been assigned;
if not, we can expect only that
the field#(-1) will be a supertype ID .
[2.29:
. now, the next job for multi-inheritance,
is accepting a message for a function to execute .
. the type mgt who accepted the multiple inheritances
was the final determiner of what a message means;
so, for example if type mgt inherits religious and hungry,
but they both implement [pass the bread],
then the type mgt in this case has to decide,
should [pass the bread] be sent to hungry, to religious,
or overridden to do something integrated ?
. thus there are 2 fixed fields in an obj:
# the dictionary of supers' ivars,
# the type mgt ID, that gets sent the message .]
. the essence of what a call to the supertype does
is manage its own ivars (instance vars)
during alloc, init, dealloc;
so, when you multi-inherit, then your call to super is
sent to each parent class .
. self`super(function)
-- this would be a good syntax because
it shows the self is being modified by a super function
which takes as arg, self and a function to send to supers .
. so how does each supertype in a multi-inheritance
know where its ivars are within the given obj?
. the first part of the object
has to be a dictionary of classes that
tells each super where their ivars are located .
. in the most general form of oop operation
there are 2 type tags:
# which type among all unrelated types:
(eg, is it a character string or a number?);
# within a type, which subtype it is:
(eg, is the number an integer, float, or quotient?).
supertype.tags can be implicit:
. we can save space in a var's storage
by ensuring that it's always assigned
values of a particular type
so that the type tag is no longer needed
because the owning subprogram's symbol table
already has it .
. if, according to the symbol table,
this object is typed,
then we can expect that
only that type has been assigned;
if not, we can expect only that
the field#(-1) will be a supertype ID .
[2.29:
. now, the next job for multi-inheritance,
is accepting a message for a function to execute .
. the type mgt who accepted the multiple inheritances
was the final determiner of what a message means;
so, for example if type mgt inherits religious and hungry,
but they both implement [pass the bread],
then the type mgt in this case has to decide,
should [pass the bread] be sent to hungry, to religious,
or overridden to do something integrated ?
. thus there are 2 fixed fields in an obj:
# the dictionary of supers' ivars,
# the type mgt ID, that gets sent the message .]
Labels:
adda,
multi-inheritance,
oop
dynamic module import
2.18: adda/cstr/dynamic module import:
. dynamic module import?
at first I was perplexed at how to parse functions
if you can't be sure what's active,
conflicting with each other in the namespace .
. but this does work out; and,
it's essential for the mandate to have
complete lisp-like control over your machine .
. lisp can treat any control structure (live or template)
as if it were also data:
inspecting its space, and then using what it finds .
. this could be called having 1st-class plug-in's .
parsing for conditional imports:
. this will be like generics, but instead of
the programmer specifying the type of instance,
the run-time is checking parameter types,
to figure out which of several subprograms to run .
. after an explicit import,
rather than just a situation where a program
looks around the file system on its own,
some of the imported names may be overloaded .
. if multiple imports are conditional,
then we must assume that any combination
of imports will happen .
. the programmer may have it arranged such that
in practice no overloading ever occurs;
but generally this can't be known at compile time .
. therefore,
we should be responding to every import
without regard to the condition intended;
and, if there is then overloading,
we should tell the compiler user
that a run-time binding has been used,
so they have the option of specifying a particular module
rather than slow things down by
testing the run-time param'type in order to
find the suitable subprogram from among
the multiplicity of modules currently in effect .
. a run-time binding works like this:
the function to call is dynamicCall,
which is given the intended subprogram's param's,
along with a link to the intended subprogram's symbol
(found in the caller's run-time symbol table);
and, that symbol has a list of pointers to
the subprograms of the same name
in the various imported modules .
. in summary,
the symbol table needs 2 listings:
one for the types it finds,
and another for the other (instance) symbols .
. in a simple example with no run-time binding,
the symbol table's list of instance symbols is temporary
(not of use after the compiler is done);
but, in the case of needing dynamic calls,
the symbol table needs a permanent list of instance symbols .
. dynamic module import?
at first I was perplexed at how to parse functions
if you can't be sure what's active,
conflicting with each other in the namespace .
. but this does work out; and,
it's essential for the mandate to have
complete lisp-like control over your machine .
. lisp can treat any control structure (live or template)
as if it were also data:
inspecting its space, and then using what it finds .
. this could be called having 1st-class plug-in's .
parsing for conditional imports:
. this will be like generics, but instead of
the programmer specifying the type of instance,
the run-time is checking parameter types,
to figure out which of several subprograms to run .
. after an explicit import,
rather than just a situation where a program
looks around the file system on its own,
some of the imported names may be overloaded .
. if multiple imports are conditional,
then we must assume that any combination
of imports will happen .
. the programmer may have it arranged such that
in practice no overloading ever occurs;
but generally this can't be known at compile time .
. therefore,
we should be responding to every import
without regard to the condition intended;
and, if there is then overloading,
we should tell the compiler user
that a run-time binding has been used,
so they have the option of specifying a particular module
rather than slow things down by
testing the run-time param'type in order to
find the suitable subprogram from among
the multiplicity of modules currently in effect .
. a run-time binding works like this:
the function to call is dynamicCall,
which is given the intended subprogram's param's,
along with a link to the intended subprogram's symbol
(found in the caller's run-time symbol table);
and, that symbol has a list of pointers to
the subprograms of the same name
in the various imported modules .
. in summary,
the symbol table needs 2 listings:
one for the types it finds,
and another for the other (instance) symbols .
. in a simple example with no run-time binding,
the symbol table's list of instance symbols is temporary
(not of use after the compiler is done);
but, in the case of needing dynamic calls,
the symbol table needs a permanent list of instance symbols .
2012-02-28
wordcoding and code paging
2.12: adda/wordcode/
code page for programming symbols:
. some places where cocoa uses strings
it means to use symbols,
a 4byte number would do it:
each library has a 16-bit serial number;
it may contain a 16-bit number of symbols .
. english words will be encoded too,
so maybe both could be part of the same coding system?
or be modular, part of its own code page .
. the programming symbols can be used alone
or the english words can embed it by saying
this is jargon from computing:
the next 4bytes belong to it .
adda/wordcode/styles of code paging:
. code paging is a system for saving space
by using shorter codes for frequently used words .
. ascii is size byte, but the sign.bit = 0 .
. there are 2 ways to signal a larger size:
# 2 bits as discriminants:
0x -> 1 byte: 7-bit space,
10 -> 2 bytes: 14-bit space
11 -> 4 bytes 30-bit space .
# sign.bit discriminant:
. sign.bit =1 means word is 2 bytes
so then word space is 15 bits .
. sign.bit=0 means 1 byte,
but reuse the control codes as discrimininants:
most serve no addx purpose except
( 9: tab, 10: newline, 13: carriage return )
all the others -- ( 0..31 -{9,10, 13} ) --
could be indicating the code pages that are
using codes of size 2, 3, or 4 bytes .
. null could be the escape,
it would mean the next byte is the size field,
and then the next string of that size
should be taken as ascii -- even the control codes .
pages for strings:
. that same string idea could apply to all code pages;
code pages would come in twins,
one for single char, and one is a string
where the 2nd byte of the string is the size,
coded like so:
0: null terminated
1 ... 127: actual size in bytes
128..255: size is {128, 256, 512, ... 2^134 } .
. you would combine these large strings
just as the number system combines large digits .
. one reason unicode did it their way
(where null was reserved for end-of-string)
is that it was preferred by unix/c coders
because it saves space if using only ascii
(no matter how long your strings are,
the size field need be only one byte wide
-- the size of your terminating null character).
. but that takes a huge chunk of 4-byte space;
considering the high-order bytes can't be zero .
. so, when do you need to communicate with unix/c?
the only time is when it not only expects no nulls,
but also expects all ascii,
so just convert to ascii at those times;
for other communications, use sockets or temp files .
2.13: prefixes and suffixes:
. some words in the 3 or 4 byte range
had a base code for finding the base word
then the extension code would indicate
the fom of the word .
. there is some main combination of prefixes and suffixes,
and then one code page can be adding the prefix word;
ie, stating which prefix combinations are being used .
. there might need to be 2 versions:
one is giving the main combinations,
(eg, -ing-ly is one combination)
the other version, for uncommon combinations,
is using word strings, eg:
anti.dis.establisment.arianism
might be 4 words .
the [all one word] codepage:
. one string code is for all one word:
if (understand) was not a common word,
it would be represented as (under, stand)
this would be independent of code page:
it is saying print the next 2 words without a space .
. another way is to use the backspace char:
every word implies adding a space afterward,
but if there's a backspace char, then it connects words
instead of separating them .
. yet another more generic function is to
have a container with 2 params:
it shows how many of the following words are contained,
that may be up to 5 bits (32 word max)
and it uses 3-bits for indicating
a style for the arrangement of the words:
{ no spaces between words
, nonbreaking spaces, dashes, underscores
, camelcasing, all initials capitalized
, underline
}.
the hash table:
. to build the word code array,
look at all text in the library;
hash each word and place in hash table;
the hash table entry has a record of stats for the word:
how it is spelled (for the sake of collisions)
and how many times it was found .
. then find the 32768 most popular words
and assign them to the shorter, 2-byte codes .
. make a new hash table of (spelling, wordcode)
for turning words into worcodes .
. make an array 0..32767 of (spelling, pre/postfix spellings)
for turning worcodes into words .
code page for programming symbols:
. some places where cocoa uses strings
it means to use symbols,
a 4byte number would do it:
each library has a 16-bit serial number;
it may contain a 16-bit number of symbols .
. english words will be encoded too,
so maybe both could be part of the same coding system?
or be modular, part of its own code page .
. the programming symbols can be used alone
or the english words can embed it by saying
this is jargon from computing:
the next 4bytes belong to it .
adda/wordcode/styles of code paging:
. code paging is a system for saving space
by using shorter codes for frequently used words .
. ascii is size byte, but the sign.bit = 0 .
. there are 2 ways to signal a larger size:
# 2 bits as discriminants:
0x -> 1 byte: 7-bit space,
10 -> 2 bytes: 14-bit space
11 -> 4 bytes 30-bit space .
# sign.bit discriminant:
. sign.bit =1 means word is 2 bytes
so then word space is 15 bits .
. sign.bit=0 means 1 byte,
but reuse the control codes as discrimininants:
most serve no addx purpose except
( 9: tab, 10: newline, 13: carriage return )
all the others -- ( 0..31 -{9,10, 13} ) --
could be indicating the code pages that are
using codes of size 2, 3, or 4 bytes .
. null could be the escape,
it would mean the next byte is the size field,
and then the next string of that size
should be taken as ascii -- even the control codes .
pages for strings:
. that same string idea could apply to all code pages;
code pages would come in twins,
one for single char, and one is a string
where the 2nd byte of the string is the size,
coded like so:
0: null terminated
1 ... 127: actual size in bytes
128..255: size is {128, 256, 512, ... 2^134 } .
. you would combine these large strings
just as the number system combines large digits .
. one reason unicode did it their way
(where null was reserved for end-of-string)
is that it was preferred by unix/c coders
because it saves space if using only ascii
(no matter how long your strings are,
the size field need be only one byte wide
-- the size of your terminating null character).
. but that takes a huge chunk of 4-byte space;
considering the high-order bytes can't be zero .
. so, when do you need to communicate with unix/c?
the only time is when it not only expects no nulls,
but also expects all ascii,
so just convert to ascii at those times;
for other communications, use sockets or temp files .
2.13: prefixes and suffixes:
. some words in the 3 or 4 byte range
had a base code for finding the base word
then the extension code would indicate
the fom of the word .
. there is some main combination of prefixes and suffixes,
and then one code page can be adding the prefix word;
ie, stating which prefix combinations are being used .
. there might need to be 2 versions:
one is giving the main combinations,
(eg, -ing-ly is one combination)
the other version, for uncommon combinations,
is using word strings, eg:
anti.dis.establisment.arianism
might be 4 words .
the [all one word] codepage:
. one string code is for all one word:
if (understand) was not a common word,
it would be represented as (under, stand)
this would be independent of code page:
it is saying print the next 2 words without a space .
. another way is to use the backspace char:
every word implies adding a space afterward,
but if there's a backspace char, then it connects words
instead of separating them .
. yet another more generic function is to
have a container with 2 params:
it shows how many of the following words are contained,
that may be up to 5 bits (32 word max)
and it uses 3-bits for indicating
a style for the arrangement of the words:
{ no spaces between words
, nonbreaking spaces, dashes, underscores
, camelcasing, all initials capitalized
, underline
}.
the hash table:
. to build the word code array,
look at all text in the library;
hash each word and place in hash table;
the hash table entry has a record of stats for the word:
how it is spelled (for the sake of collisions)
and how many times it was found .
. then find the 32768 most popular words
and assign them to the shorter, 2-byte codes .
. make a new hash table of (spelling, wordcode)
for turning words into worcodes .
. make an array 0..32767 of (spelling, pre/postfix spellings)
for turning worcodes into words .
portable cross-volume hardlinks
2012.2.26: adde/fs/volume id for cross-volume linking,
[2011.10.2: preface:
. addx is meant to be a portable environment
available for mac, linux, pc, ...;
and one problem to be faced
is a filesystem that has portable links:
they are all incompatible with each other,
except where mac and linux use unix links;
but those are not generally useful;
eg, I can't put a unix link on a fat32 volume,
not even a symbolic (vs hard) link?! [12.2.26:
( a symbolic link is just a text file
that includes the pathname of the resource);
one problem with unix allowing a link on fat32
is that it can be seen by multiple unix versions
each with its own style of pathnames:
# mac unix: /Volumes/myDrive/
# linux unix: /media/myDrive/
but that problem would be true for any removable drive,
not just one formatted with fat32 .
. what's peculiar about fat32 is a competing link format .
. it appears the volume's file system
is responsible for supporting links,
when what is needed is to have a file type
associated with link data ).]
. Apple has a friendly link that works in {mac,fat32},
and it keeps pointing to its target
even if you move the target;
however, each such link weighs half a megabyte!
[2011.10.2: intro:
. for link targets to be recognized across all platforms,
the portable filesystem manager (adde)
must have its own way to identify
every possible link target,
and all the volumes they could be on .]
2012.2.26: converting other OS's links:
. when dealing with other links
(those created by {windows, linux, mac})
adde needs to convert these .
. other apps see the addx link as a text file,
but when asking adde to traverse the file system,
it will follow the link's directions .
12.2.27: tracking unwritable volumes:
. any time a new volume is mounted
adde tries to register it by adding the volume ID;
however, some volumes are not writable,
so they can't be registered in the usual way;
in that case,
adde needs a list of those volumes that were
found to be unregisterable .
. does each volume have some readable serial#?
. you can't depend on checksumming;
because, being unwritable doesn't mean it can't be
modified by another platform
(eg, a writable mac volume will be
unwritable on linux);
so, the only reliable way is to
keep a list of unregisterable volumes,
and ask user which one this is .
. the menu should be sorted by device;
for instance, if this is a mac volume on usb,
there's no use showing cd's on the list).
12.2.27: the 3 types of pointers:
. filenames are pointers to content units;
links are usually considered to be aliases,
where pointers are sharing the same target .
. there are subtle differences of intention
among the various uses of pointers:
# the absolute address:
. goto whatever's at this address
(the address includes the filename
but not the file being named);
if nothing's at this address,
then make a new file with this filename .
# the relative address:
. use the address relative to some ancestor folder
or relative to the current volume,
rather than at a specific full path .
# the object reference:
. stay connected to what's currently at this address
(at the time the link was created);
if the file was moved, then find that file again .
. adde is putting the file ID inside the file;
that makes it easy to stay linked to an object reference .
2012.2.26: types of link exceptions:
# broken link:
. the target file was moved or renamed;
# unmounted volume:
. the target volume is not currently available .
. adde has agreements with the user
for each type of link exception,
whether to report exceptions via mailbox,
or interrupt the user with an alert dialog .
2011.9.2: details:
. adde is assigning a unique ID to every
volume, folder, and file; [12.2.28:
within the addx filesystem only:
for external files the object linking is less robust .]
. since volumes can be shared among acct's,
the volume itself must have a file ID database;
and then each acct must use that to update
the ID database kept on the acct's volume .
. mac's .dmg (disk image) is a virtual volume:
the enclosing volume considers it to be one file,
but after mounting it, it's like an external drive;
so, when looking for volumes to register,
it needs to be on the look-out for mounted .dmg's .
2012.2.26:
. the volume ID has 2 parts:
# the name of the acct that created it;
# the date of this volume's registration .
. the user's ID could be something like their email address,
or a social networking acct address .
file ID uniqueness:
. if there is an endless stream of creations and deletions,
then a volume could run out of file-ID's;
whereas, if they were reused,
then we must make sure there are no clashes;
so, the file ID should include the creation date .
[12.2.28:
. the file ID in a volume database
is specific to that volume
so it need be nothing more than a timestamp,
but that's only true for an infinite precision timestamp;
because, if the timestamp changes only every second,
then the ID needs a serial number for the situation where
the user has asked for thousands of links,
and they were all generated within one second .
. alt'ly, we could keep track of the last timestamp used,
and then we'd have use of
every timestamp between then and now .
... so then it seems,
the simplest idea is to have a serial number
but one of infinite type, like dates are:
we never run out of file-ID's
because we can just keep adding digits .]
[12.2.28: the addx file ID:
. this article has used the same term, file ID,
for both a volume database index,
and for the addx file ID tag inside every file .
. the addx internal file ID is formatted as
creation.date & subject name
but if these files are moved to a shared drive
then to make the ID unique,
the creators name will need to be added .
. and so, in anticipation of this,
an object reference link should always include
the author's name like so:
. check the addx file for an author's name,
if it has none,
then the link's object identifier should include
the name of the person making the link
since it is their acct,
and the file's in it are by default theirs .]
2012.2.26: volume db separate vs integrated:
. in building a volume's file ID database,
the user has the option of efficiency or less clutter:
. some are not happy about hidden system files
because when you bring your removable to another OS,
all the hidden files become visible .
. if hidden folders are considered clutter,
then adde could avoid such clutter by
building a 2nd partial folder system
instead of reusing the current one .
12.2.27: the acct db:
. each user's acct needs an acct database
that contains the list of familiar volume ID's .
. when a link is being resolved
it first has to translate the volume ID
into the string understood by the current OS .
. it has a list of mounted volumes
and expects each to have an adde system file,
containing the volume's ID
and the file ID database .
. it then collects these from each volume
into the acct database
in a table of (volumes currently mounted)
that provides the maps:
volume ID -> volume pathname,
and its inverse .
. any time adde makes a link across volumes
it uses this table to convert the volume's name
into the corresponding volume ID .
12.2.27: sorting unmountables:
. a volume shared with other users
could have links to
volumes that are unknown to the user's acct
so the acct database has 3 lists:
# volumes known to user:
(mountable even if not currently mounted)
# unmountable volumes:
(user indicated these can't be found)
# volumes not asked about yet:
(we won't ask a user whether a volume is mountable
until they click on a link that targets that volume).
12.2.27: volume database has a list of target volumes:
. for each volume, self,
if any of the links on self are
pointing into a volume, v, other than self,
then v's volume ID should be copied into
self's list of target volumes .
. for each volume ID on this list,
there is volume meta info,
(such as a user hint about how to
locate and identify the volume;
or a picture of the removable media);
and during a mount, this volume meta info is
copied into the acct database to build the
table of (volumes currently mounted).
2012.2.26: version# simple links:
. the simplest capability doesn't include
dealing with broken links;
it is creating links and having an engine for
translating them into system-specific links .
. in version# simple links, the link has 3 parts:
# a text string indicating the pathname
(either absolute or relative);
# a volume ID .
[12.2.28:
. those 2 fields specify an file address
(ie, a pointer to a file with a given name)
but for an object reference
(where we are tracking a particular file)
there could also be a 3rd part:
# file ID:
. an object reference means that
when you get to this address,
make sure the file there is the one I had linked to .
. the file's data should include the indicated file ID .
. a file ID can also be used for
jumping into the middle of a file,
to point at a subfolder .
. if the volume and address are unspecified
then it means search for this file ID,
and return me a folder of links to any files containing it .]
2012.2.26: version# broken link finder:
[12.2.28: intro:
. in this advanced version,
we not only make a universal link,
but also repair links that are missing targets .
. of course, this concerns only links to
object references (particular content blocks)
rather than address references
which require only a particular pathname .]
. it might be the case that, after a file rename,
the only way to tell a file's identity
is by searching for the same attributes:
(size, modify date, checksum).
. if the file has been modified and moved or renamed
we might still be able to find the identity
by checking for partial checksums .
. this is possible for files like text,
where blank lines naturally define paragraphs .
. of course in the case of addx files,
we just look inside the file for the file ID
rather than relying on the file's name .
. we cannot assume that every file system will
divide the job into file pointers and content nodes;
therefore we can't depend on
hardlinks to provide a sort of file ID .
12.2.27: web: fat32 hardlink limitations:
. in fat32, the directory entries contain
file pointers rather than handles:
they tell you where on the disk the content is,
rather than where an immovable info node is
that will contain the current pointer;
so then compacting the drive moves the files
thus breaking any hardlinks you had .
. and if you delete a link's target file,
then your hardlinks are pointing at garbage .
. here's a unix command for making hardlinks in FAT32:
mount -o bind /origdir /newdir
. chkdsk will "fix" hardlinks:
. it reports them as cross-links and repairs by
making copies for each alias to own .
. fat32 symbolic links (aka shortcuts)
are before the era of POSIX symbolic links
which are supported by Windows only in Vista+ .
. to support version# broken link finder,
the link's 3rd part, file ID, becomes mandatory .
. back at the volume where the target is,
the file ID locates meta info about that file:
(size, checksum, name
, current url (a cache built from folder list)
, pointer to parent folder
)
. and from there it has the full chain of folders
because each folder has a pointer to its parent folder
(2011: doing it that way saves a lot of
file pathname rewrites
when one of the top level folders gets moved ).
. if the folder system has not been modified recently
then this goes very quickly because
the file meta info includes the full pathname
but if things have changed, then that cache will be stale,
and it has to rebuild the cache by
following the chain of parent folders
and copying their name strings into a unix pathname .
. if the link is dangling,
and the volume database is in a separate folder
rather than integrated with the volume's file system
then it needs to sync the database
with the current file system . [12.2.27:
. the database is only a partial copy of the file system
since the only files included are the aliased ones,
and the only folders included
are the ones that contain the aliased files .]
. to see if the missing file was just moved,
search everywhere starting on the expected volume;
if still not found,
then ask the user whether to search more
or just use a backup .
. if the missing file was both moved and renamed
then this could be a case where
the file has been repurposed,
and so the link should just be deleted .
. the user may know what to do,
but some file changes are made by programs .
[12.2.28:
. a (move, rename, modify) of a non-addx file
is usually indistinguishable from a {delete, create};
and, if the name is quite common,
then a (move, modify) is not always fixable either .
. if it was a text file, then adde would have done
some partial checksums on it,
and in that case, the file is likely findable
because a file modification doesn't usually affect
every single paragraph in the file .
. adde needs to run in the background
and watch the file system for changes .
. modifications can be quite frequent,
so, adde has to be watching first for
file renames and moves,
and check with the volume's file ID database
for whether that's an aliased file or not .
. it should then check for file changes
in order to promptly update partial checksums .]
[2011.10.2: preface:
. addx is meant to be a portable environment
available for mac, linux, pc, ...;
and one problem to be faced
is a filesystem that has portable links:
they are all incompatible with each other,
except where mac and linux use unix links;
but those are not generally useful;
eg, I can't put a unix link on a fat32 volume,
not even a symbolic (vs hard) link?! [12.2.26:
( a symbolic link is just a text file
that includes the pathname of the resource);
one problem with unix allowing a link on fat32
is that it can be seen by multiple unix versions
each with its own style of pathnames:
# mac unix: /Volumes/myDrive/
# linux unix: /media/myDrive/
but that problem would be true for any removable drive,
not just one formatted with fat32 .
. what's peculiar about fat32 is a competing link format .
. it appears the volume's file system
is responsible for supporting links,
when what is needed is to have a file type
associated with link data ).]
. Apple has a friendly link that works in {mac,fat32},
and it keeps pointing to its target
even if you move the target;
however, each such link weighs half a megabyte!
[2011.10.2: intro:
. for link targets to be recognized across all platforms,
the portable filesystem manager (adde)
must have its own way to identify
every possible link target,
and all the volumes they could be on .]
2012.2.26: converting other OS's links:
. when dealing with other links
(those created by {windows, linux, mac})
adde needs to convert these .
. other apps see the addx link as a text file,
but when asking adde to traverse the file system,
it will follow the link's directions .
12.2.27: tracking unwritable volumes:
. any time a new volume is mounted
adde tries to register it by adding the volume ID;
however, some volumes are not writable,
so they can't be registered in the usual way;
in that case,
adde needs a list of those volumes that were
found to be unregisterable .
. does each volume have some readable serial#?
. you can't depend on checksumming;
because, being unwritable doesn't mean it can't be
modified by another platform
(eg, a writable mac volume will be
unwritable on linux);
so, the only reliable way is to
keep a list of unregisterable volumes,
and ask user which one this is .
. the menu should be sorted by device;
for instance, if this is a mac volume on usb,
there's no use showing cd's on the list).
12.2.27: the 3 types of pointers:
. filenames are pointers to content units;
links are usually considered to be aliases,
where pointers are sharing the same target .
. there are subtle differences of intention
among the various uses of pointers:
# the absolute address:
. goto whatever's at this address
(the address includes the filename
but not the file being named);
if nothing's at this address,
then make a new file with this filename .
# the relative address:
. use the address relative to some ancestor folder
or relative to the current volume,
rather than at a specific full path .
# the object reference:
. stay connected to what's currently at this address
(at the time the link was created);
if the file was moved, then find that file again .
. adde is putting the file ID inside the file;
that makes it easy to stay linked to an object reference .
2012.2.26: types of link exceptions:
# broken link:
. the target file was moved or renamed;
# unmounted volume:
. the target volume is not currently available .
. adde has agreements with the user
for each type of link exception,
whether to report exceptions via mailbox,
or interrupt the user with an alert dialog .
2011.9.2: details:
. adde is assigning a unique ID to every
volume, folder, and file; [12.2.28:
within the addx filesystem only:
for external files the object linking is less robust .]
. since volumes can be shared among acct's,
the volume itself must have a file ID database;
and then each acct must use that to update
the ID database kept on the acct's volume .
. mac's .dmg (disk image) is a virtual volume:
the enclosing volume considers it to be one file,
but after mounting it, it's like an external drive;
so, when looking for volumes to register,
it needs to be on the look-out for mounted .dmg's .
2012.2.26:
. the volume ID has 2 parts:
# the name of the acct that created it;
# the date of this volume's registration .
. the user's ID could be something like their email address,
or a social networking acct address .
file ID uniqueness:
. if there is an endless stream of creations and deletions,
then a volume could run out of file-ID's;
whereas, if they were reused,
then we must make sure there are no clashes;
so, the file ID should include the creation date .
[12.2.28:
. the file ID in a volume database
is specific to that volume
so it need be nothing more than a timestamp,
but that's only true for an infinite precision timestamp;
because, if the timestamp changes only every second,
then the ID needs a serial number for the situation where
the user has asked for thousands of links,
and they were all generated within one second .
. alt'ly, we could keep track of the last timestamp used,
and then we'd have use of
every timestamp between then and now .
... so then it seems,
the simplest idea is to have a serial number
but one of infinite type, like dates are:
we never run out of file-ID's
because we can just keep adding digits .]
[12.2.28: the addx file ID:
. this article has used the same term, file ID,
for both a volume database index,
and for the addx file ID tag inside every file .
. the addx internal file ID is formatted as
creation.date & subject name
but if these files are moved to a shared drive
then to make the ID unique,
the creators name will need to be added .
. and so, in anticipation of this,
an object reference link should always include
the author's name like so:
. check the addx file for an author's name,
if it has none,
then the link's object identifier should include
the name of the person making the link
since it is their acct,
and the file's in it are by default theirs .]
2012.2.26: volume db separate vs integrated:
. in building a volume's file ID database,
the user has the option of efficiency or less clutter:
. some are not happy about hidden system files
because when you bring your removable to another OS,
all the hidden files become visible .
. if hidden folders are considered clutter,
then adde could avoid such clutter by
building a 2nd partial folder system
instead of reusing the current one .
12.2.27: the acct db:
. each user's acct needs an acct database
that contains the list of familiar volume ID's .
. when a link is being resolved
it first has to translate the volume ID
into the string understood by the current OS .
. it has a list of mounted volumes
and expects each to have an adde system file,
containing the volume's ID
and the file ID database .
. it then collects these from each volume
into the acct database
in a table of (volumes currently mounted)
that provides the maps:
volume ID -> volume pathname,
and its inverse .
. any time adde makes a link across volumes
it uses this table to convert the volume's name
into the corresponding volume ID .
12.2.27: sorting unmountables:
. a volume shared with other users
could have links to
volumes that are unknown to the user's acct
so the acct database has 3 lists:
# volumes known to user:
(mountable even if not currently mounted)
# unmountable volumes:
(user indicated these can't be found)
# volumes not asked about yet:
(we won't ask a user whether a volume is mountable
until they click on a link that targets that volume).
12.2.27: volume database has a list of target volumes:
. for each volume, self,
if any of the links on self are
pointing into a volume, v, other than self,
then v's volume ID should be copied into
self's list of target volumes .
. for each volume ID on this list,
there is volume meta info,
(such as a user hint about how to
locate and identify the volume;
or a picture of the removable media);
and during a mount, this volume meta info is
copied into the acct database to build the
table of (volumes currently mounted).
2012.2.26: version# simple links:
. the simplest capability doesn't include
dealing with broken links;
it is creating links and having an engine for
translating them into system-specific links .
. in version# simple links, the link has 3 parts:
# a text string indicating the pathname
(either absolute or relative);
# a volume ID .
[12.2.28:
. those 2 fields specify an file address
(ie, a pointer to a file with a given name)
but for an object reference
(where we are tracking a particular file)
there could also be a 3rd part:
# file ID:
. an object reference means that
when you get to this address,
make sure the file there is the one I had linked to .
. the file's data should include the indicated file ID .
. a file ID can also be used for
jumping into the middle of a file,
to point at a subfolder .
. if the volume and address are unspecified
then it means search for this file ID,
and return me a folder of links to any files containing it .]
2012.2.26: version# broken link finder:
[12.2.28: intro:
. in this advanced version,
we not only make a universal link,
but also repair links that are missing targets .
. of course, this concerns only links to
object references (particular content blocks)
rather than address references
which require only a particular pathname .]
. it might be the case that, after a file rename,
the only way to tell a file's identity
is by searching for the same attributes:
(size, modify date, checksum).
. if the file has been modified and moved or renamed
we might still be able to find the identity
by checking for partial checksums .
. this is possible for files like text,
where blank lines naturally define paragraphs .
. of course in the case of addx files,
we just look inside the file for the file ID
rather than relying on the file's name .
. we cannot assume that every file system will
divide the job into file pointers and content nodes;
therefore we can't depend on
hardlinks to provide a sort of file ID .
12.2.27: web: fat32 hardlink limitations:
. in fat32, the directory entries contain
file pointers rather than handles:
they tell you where on the disk the content is,
rather than where an immovable info node is
that will contain the current pointer;
so then compacting the drive moves the files
thus breaking any hardlinks you had .
. and if you delete a link's target file,
then your hardlinks are pointing at garbage .
. here's a unix command for making hardlinks in FAT32:
mount -o bind /origdir /newdir
. chkdsk will "fix" hardlinks:
. it reports them as cross-links and repairs by
making copies for each alias to own .
. fat32 symbolic links (aka shortcuts)
are before the era of POSIX symbolic links
which are supported by Windows only in Vista+ .
. to support version# broken link finder,
the link's 3rd part, file ID, becomes mandatory .
. back at the volume where the target is,
the file ID locates meta info about that file:
(size, checksum, name
, current url (a cache built from folder list)
, pointer to parent folder
)
. and from there it has the full chain of folders
because each folder has a pointer to its parent folder
(2011: doing it that way saves a lot of
file pathname rewrites
when one of the top level folders gets moved ).
. if the folder system has not been modified recently
then this goes very quickly because
the file meta info includes the full pathname
but if things have changed, then that cache will be stale,
and it has to rebuild the cache by
following the chain of parent folders
and copying their name strings into a unix pathname .
. if the link is dangling,
and the volume database is in a separate folder
rather than integrated with the volume's file system
then it needs to sync the database
with the current file system . [12.2.27:
. the database is only a partial copy of the file system
since the only files included are the aliased ones,
and the only folders included
are the ones that contain the aliased files .]
. to see if the missing file was just moved,
search everywhere starting on the expected volume;
if still not found,
then ask the user whether to search more
or just use a backup .
. if the missing file was both moved and renamed
then this could be a case where
the file has been repurposed,
and so the link should just be deleted .
. the user may know what to do,
but some file changes are made by programs .
[12.2.28:
. a (move, rename, modify) of a non-addx file
is usually indistinguishable from a {delete, create};
and, if the name is quite common,
then a (move, modify) is not always fixable either .
. if it was a text file, then adde would have done
some partial checksums on it,
and in that case, the file is likely findable
because a file modification doesn't usually affect
every single paragraph in the file .
. adde needs to run in the background
and watch the file system for changes .
. modifications can be quite frequent,
so, adde has to be watching first for
file renames and moves,
and check with the volume's file ID database
for whether that's an aliased file or not .
. it should then check for file changes
in order to promptly update partial checksums .]
Labels:
adde,
journaled fs
kindle++ (emulating a book)
2.23: adde/kindle++ (emulating a book):
. to be like a book
kindle needs a virtual sideview of the book
so you see an array of pages,
then you open book at a page .
. you can cursor down approximates page,
and then brushing sideways provides
fine adjustment of page selection .
. it can show recent and frequent pages as being wider,
and it can show page number and subtitles of current page
which would be even better than a book .
[2.28:
. you can have a toc not of the book's content
but of all your notes and starred pages .]
. to be like a book
kindle needs a virtual sideview of the book
so you see an array of pages,
then you open book at a page .
. you can cursor down approximates page,
and then brushing sideways provides
fine adjustment of page selection .
. it can show recent and frequent pages as being wider,
and it can show page number and subtitles of current page
which would be even better than a book .
[2.28:
. you can have a toc not of the book's content
but of all your notes and starred pages .]
2012-02-27
efficiently panning large documents
2011.9.15: adde/gui/efficiently panning large documents:
. when a window is much smaller than
the document of a network graph,
do you have to keep the whole bit-image in memory?
[9.18:
. the ideal is having a small engine that is
generating a small data set as-needed,
expanding from drawing instructions
into bit maps,
rather than sending expanded pages to off-ram storage;
then again,
speedy solid-state drives are getting common,
and energy is getting precious ... .]
. for saving energy,
a network graph is stored as an image;
for save space and hard drive accesses,
it would be a list of nodes with attributes:
(inout edges, global position, ...).
. a search function given window area
would return any nodes within that region .
. I had this mem-saving scheme for drawing it:
rather than allow panning,
move to birdseye view (zoom out some),
then set your zoom-in box to go there;
the window sized image is kept in memory,
but few or no closups are cached .
. this idea is not that important on a fast computer;
because, you can respond on the fly:
. whichever way the user is panning
find the sections about to be exposed,
and create the images just in time .
. for each section,
you need to know which nodes are in that section,
and then to draw the edges,
you need to know the nodes that connect to
your drawn nodes;
the edge path is a style of line
{linear, Bézier curve, ...}
between the global positions of 2 nodes
which is then mapped across any needed section
but drawn only on currently existing sections
(those expected to be viewed soon).
9.16: edges as objects:
. to help speed things up
by quickly finding per-section edge lists,
you could have an edges list too;
each edge would know:
# the locations of its end-point nodes;
# the points that define how it curves;
# a list of the sections
that the edge's line runs through .
9.16: space walking:
. if you have nodes and edges in 3-d,
then you may want to follow an edge
and see things nearby along the way;
this can be done with some of the previous ideas:
. a line function is a series of global position points,
and for each point you figure the 3-d region,
then you know the nearby regions,
and finally,
you can search the edges list for a region,
to get a list of every edge intersecting that region .
9.16: web.adde/gui/terminology:
. how is the graphics industry using "(sector)?
Portal rendering:
. when a window is much smaller than
the document of a network graph,
do you have to keep the whole bit-image in memory?
[9.18:
. the ideal is having a small engine that is
generating a small data set as-needed,
expanding from drawing instructions
into bit maps,
rather than sending expanded pages to off-ram storage;
then again,
speedy solid-state drives are getting common,
and energy is getting precious ... .]
. for saving energy,
a network graph is stored as an image;
for save space and hard drive accesses,
it would be a list of nodes with attributes:
(inout edges, global position, ...).
. a search function given window area
would return any nodes within that region .
. I had this mem-saving scheme for drawing it:
rather than allow panning,
move to birdseye view (zoom out some),
then set your zoom-in box to go there;
the window sized image is kept in memory,
but few or no closups are cached .
. this idea is not that important on a fast computer;
because, you can respond on the fly:
. whichever way the user is panning
find the sections about to be exposed,
and create the images just in time .
. for each section,
you need to know which nodes are in that section,
and then to draw the edges,
you need to know the nodes that connect to
your drawn nodes;
the edge path is a style of line
{linear, Bézier curve, ...}
between the global positions of 2 nodes
which is then mapped across any needed section
but drawn only on currently existing sections
(those expected to be viewed soon).
9.16: edges as objects:
. to help speed things up
by quickly finding per-section edge lists,
you could have an edges list too;
each edge would know:
# the locations of its end-point nodes;
# the points that define how it curves;
# a list of the sections
that the edge's line runs through .
9.16: space walking:
. if you have nodes and edges in 3-d,
then you may want to follow an edge
and see things nearby along the way;
this can be done with some of the previous ideas:
. a line function is a series of global position points,
and for each point you figure the 3-d region,
then you know the nearby regions,
and finally,
you can search the edges list for a region,
to get a list of every edge intersecting that region .
9.16: web.adde/gui/terminology:
. how is the graphics industry using "(sector)?
Portal rendering:
In computer-generated imagery
and real-time 3D computer graphics,
portal rendering is an algorithm
for visibility determination.
For example,
consider a 3D computer game environment,
which may contain many polygons,
only a few of which may be visible on screen
at a given time.
A portal system is based on using
the partitioning of space
to form generalizations about
the visibility of objects within those spaces.
Regions of map space are divided into
polygonal, generally convex, areas called sectors.
Adjacent sectors are linked to one another via
shared dividing polygons termed portals.
Approaches that pre-compute visibility for sectors
are referred to as PVS (potentially visible set) methods.
Labels:
adde,
algorithms,
gui
2012-01-31
correctness vs capability constraints
1.7: pos.addx/security/correctness vs capability constraints:
. I'm awed at the complexity of Ada;
they go to great lengths to
help you ensure program correctness;
but I doubt it can be used by the public .
. I think it would be sufficient to ensure only that
module capabilities were expressable and enforceable;
eg, any routes to implied sideaffects
need to be declared by a module .
. if parameters have links to caller`space,
then lack of an out-mode declaration
should by an assurance that the param
has no sideaffects .
[1.8:
. when the users call an app,
they expect know its capability limits,
yet they may also expect dynamic updates,
which could change the set of
subprograms called by the app .
. how does the user stay updated to
implied changes in app capability limits,
when the app has been linked to
more powerful subprograms ?
( you might assume that if you can trust a subprogram,
then you can trust apps to use that subprogram;
a counter example is when a worker has
top security clearance to work with your gov,
but you can't allow that work to be
employed by foreign gov's) .]
. if a subprogram has capabilities that are
greater than the app calling it,
then the app needs to
declare these enabling subprograms,
or the app's stated capabilities need to be
a function of whatever the app links into
dynamically .
. if the app's capabilities changed since
the user's last ok,
then the ok from user or mgt
has to happen again,
else the app can't be allowed to run .
. I'm awed at the complexity of Ada;
they go to great lengths to
help you ensure program correctness;
but I doubt it can be used by the public .
. I think it would be sufficient to ensure only that
module capabilities were expressable and enforceable;
eg, any routes to implied sideaffects
need to be declared by a module .
. if parameters have links to caller`space,
then lack of an out-mode declaration
should by an assurance that the param
has no sideaffects .
[1.8:
. when the users call an app,
they expect know its capability limits,
yet they may also expect dynamic updates,
which could change the set of
subprograms called by the app .
. how does the user stay updated to
implied changes in app capability limits,
when the app has been linked to
more powerful subprograms ?
( you might assume that if you can trust a subprogram,
then you can trust apps to use that subprogram;
a counter example is when a worker has
top security clearance to work with your gov,
but you can't allow that work to be
employed by foreign gov's) .]
. if a subprogram has capabilities that are
greater than the app calling it,
then the app needs to
declare these enabling subprograms,
or the app's stated capabilities need to be
a function of whatever the app links into
dynamically .
. if the app's capabilities changed since
the user's last ok,
then the ok from user or mgt
has to happen again,
else the app can't be allowed to run .
addx's text or lexical handler
1.3: addx/addt (text handler):
[1.31: update:
addl is the lui = lexical user interface;
"(addle) also means unable to think clearly
-- just how many feel around terminals
or any command line interface! ]
[1.6: summary:
. my original vision of the addx system
would avoid the use of shell,
replacing all use of it with adde;
but in case people would prefer access via shell,
there should be a module specific to that need .
. the essential feature of other shells,
is that they use text as both the input and output,
hence the name add`text .
. the shell lets you pipe outputs of one command
to the inputs of another command,
and they all assume you are sending a text stream .
. the addt module presents a set of commands
that provide shell equivalents for everything in adde .
. the addt commands are wrappers
around addx commands that do translations
from adda and addm word code to equivalent ascii versions .
. if the addx equivalents need to be piped to or from
native shell commands,
then addt offers a translation between the native text,
and addx binary communications:
eg, some-unix-cmd | a2t | adda | t2a | another-unix-cmd .
. another idea, to avoid explicit use of {a2t, t2a},
is to have one shell within a shell like python has,
but it would emulate the native shell's language,
so that while you were still dealing with your favorite shell,
you could also mix it with addx library calls,
by having addt insert the needed conversion filters
before passing it on to the actual shell .]
1.3: intro:
. the c`main`argv and unix`conventions
(esp'ly the borne shell)
determine how the user at a command line
can communicate with a program:
the cli or shell determine how a command is parsed
into the array of ascii strings that the program sees .
1.3: first idea:
. addt is a cli tool that is first responder to
any text inputs:
. it converts text to ascii byte code
which can be passed to `main's argv .
. need to define an addx byte code that
represents addm and etree as ascii rather than ints .
[1.31: update:
addl is the lui = lexical user interface;
"(addle) also means unable to think clearly
-- just how many feel around terminals
or any command line interface! ]
[1.6: summary:
. my original vision of the addx system
would avoid the use of shell,
replacing all use of it with adde;
but in case people would prefer access via shell,
there should be a module specific to that need .
. the essential feature of other shells,
is that they use text as both the input and output,
hence the name add`text .
. the shell lets you pipe outputs of one command
to the inputs of another command,
and they all assume you are sending a text stream .
. the addt module presents a set of commands
that provide shell equivalents for everything in adde .
. the addt commands are wrappers
around addx commands that do translations
from adda and addm word code to equivalent ascii versions .
. if the addx equivalents need to be piped to or from
native shell commands,
then addt offers a translation between the native text,
and addx binary communications:
eg, some-unix-cmd | a2t | adda | t2a | another-unix-cmd .
. another idea, to avoid explicit use of {a2t, t2a},
is to have one shell within a shell like python has,
but it would emulate the native shell's language,
so that while you were still dealing with your favorite shell,
you could also mix it with addx library calls,
by having addt insert the needed conversion filters
before passing it on to the actual shell .]
1.3: intro:
. the c`main`argv and unix`conventions
(esp'ly the borne shell)
determine how the user at a command line
can communicate with a program:
the cli or shell determine how a command is parsed
into the array of ascii strings that the program sees .
1.3: first idea:
. addt is a cli tool that is first responder to
any text inputs:
. it converts text to ascii byte code
which can be passed to `main's argv .
. need to define an addx byte code that
represents addm and etree as ascii rather than ints .
security per use case
1.1: addx/security per use case:
. know your users, the security book advises?
a corollary is:
make it clear in both the code's logic
and in the user's doc's,
what you expect of users .
. it was talking about the problem of
making security a hassle for users,
when, if you thought it out better,
you could find just the security measures you need
for their use case, and then bake just that in .
. one thing I recall hating
is not knowing all the dead ends upfront .
. there's all these things that can't be done,
and you can't know about it because
"(this app is so easy, intuitive, no thick manuals, etc ).
...
. sometimes you might not know what your users expect;
so then the menu's should have a search box
in addition to the menu hierarchy;
and, if a search returns nothing,
you ask them to explain what they want that is missing .
for touchscreen users,
and for those not familiar with terminology,
use a set of menus for identifying how features are
grouped by what kinds of things they do,
and by what the feature is called .
. let the users pick a place in that tree,
and optionally give a sentence for detailing
what's missing from the tree .
. a google app engine site could
merge all these requests and build the tree;
the tree will also be offline but not always uptodate .
. know your users, the security book advises?
a corollary is:
make it clear in both the code's logic
and in the user's doc's,
what you expect of users .
. it was talking about the problem of
making security a hassle for users,
when, if you thought it out better,
you could find just the security measures you need
for their use case, and then bake just that in .
. one thing I recall hating
is not knowing all the dead ends upfront .
. there's all these things that can't be done,
and you can't know about it because
"(this app is so easy, intuitive, no thick manuals, etc ).
...
. sometimes you might not know what your users expect;
so then the menu's should have a search box
in addition to the menu hierarchy;
and, if a search returns nothing,
you ask them to explain what they want that is missing .
for touchscreen users,
and for those not familiar with terminology,
use a set of menus for identifying how features are
grouped by what kinds of things they do,
and by what the feature is called .
. let the users pick a place in that tree,
and optionally give a sentence for detailing
what's missing from the tree .
. a google app engine site could
merge all these requests and build the tree;
the tree will also be offline but not always uptodate .
addm's case instruction
addm/cstr/case/large domain space issues:
[1.8: intro:
. for a classic case stmt, one ensuring that
no more than one exec'path was activated,
the primary purpose of the variables (and arithmetic)
is to dynamically set the guard ranges .]
if case ranges can be variable expressions,
how does that work at the machine level?
. the alternative execution paths are numbered: 0...n,
so the case stmt is an array 0..n of
pointer to subroutine .
. the pointer could be an offset of the program counter,
so they can be word sized or even byte sized .
[1.8: case method depends on domain size:
. typically for each exec'path,
there is either a list of literals,
or else a pair of possibly variable expressions
delimiting a range .
. next there are 2 cases of domain space:
# small:
. the expression being cased is less than a byte,
or certainly not more than a 16bit word .
. in this case there is a direct mapping
from enum to exec'path number .
. we sort the literal cases,
thus allowing for a binary search during run-time .
. for the case ranges, a..b, c..d, ...,
we need the if/else if ... list:
case => a and case <= b ?
goto ...
else case => c and case <= d ?
goto ...
else ... .
# huge: ... ]
large domain space issues:
. how do the cases map to 0..n
when not enum literals?
that's when it loses the efficiency
that case stmt's are known for:
. it's eval'ing every exec'path guard expression
as well as the expression being cased,
then it might be reduced to crawling through
a huge {if/else if ...} list;
what it checks first might depend on profiling:
in the past eval's of this case stmt,
what percentage of time was each case chosen?
1.8: hashing intro:
. the expression is larger than small;
in this case, hashing might work?
in a hash the typical problem is
associating a name with an id# .
. when you find the name,
then you need to replace it with the id#;
you could place the string in a sorted container
in which the insertion operation was cheap;
and then do a binary search to find it,
or you could use the hash method:
. if you expect n strings,
then use an algorithm to turn the string into
a number that can range of n values;
eg, if there are less than 2*^16 values,
then your hash function should return 16bit ints .
. if 2 strings result in the same number
then they both go in the same bucket,
so when your search finds a bucket,
it has to crawl as with the binary search .
1.8: back to the casing problem:
. if the expression being cased is a huge number or string,
then with the literals used in the guard
we build a hash table,
and then hash the value being cased .
. when we find the match,
it's associated with the exec'path number we need .
[1.8: intro:
. for a classic case stmt, one ensuring that
no more than one exec'path was activated,
the primary purpose of the variables (and arithmetic)
is to dynamically set the guard ranges .]
if case ranges can be variable expressions,
how does that work at the machine level?
. the alternative execution paths are numbered: 0...n,
so the case stmt is an array 0..n of
pointer to subroutine .
. the pointer could be an offset of the program counter,
so they can be word sized or even byte sized .
[1.8: case method depends on domain size:
. typically for each exec'path,
there is either a list of literals,
or else a pair of possibly variable expressions
delimiting a range .
. next there are 2 cases of domain space:
# small:
. the expression being cased is less than a byte,
or certainly not more than a 16bit word .
. in this case there is a direct mapping
from enum to exec'path number .
. we sort the literal cases,
thus allowing for a binary search during run-time .
. for the case ranges, a..b, c..d, ...,
we need the if/else if ... list:
case => a and case <= b ?
goto ...
else case => c and case <= d ?
goto ...
else ... .
# huge: ... ]
large domain space issues:
. how do the cases map to 0..n
when not enum literals?
that's when it loses the efficiency
that case stmt's are known for:
. it's eval'ing every exec'path guard expression
as well as the expression being cased,
then it might be reduced to crawling through
a huge {if/else if ...} list;
what it checks first might depend on profiling:
in the past eval's of this case stmt,
what percentage of time was each case chosen?
1.8: hashing intro:
. the expression is larger than small;
in this case, hashing might work?
in a hash the typical problem is
associating a name with an id# .
. when you find the name,
then you need to replace it with the id#;
you could place the string in a sorted container
in which the insertion operation was cheap;
and then do a binary search to find it,
or you could use the hash method:
. if you expect n strings,
then use an algorithm to turn the string into
a number that can range of n values;
eg, if there are less than 2*^16 values,
then your hash function should return 16bit ints .
. if 2 strings result in the same number
then they both go in the same bucket,
so when your search finds a bucket,
it has to crawl as with the binary search .
1.8: back to the casing problem:
. if the expression being cased is a huge number or string,
then with the literals used in the guard
we build a hash table,
and then hash the value being cased .
. when we find the match,
it's associated with the exec'path number we need .
integrated app tutorials
1.22: adde/integrated demo's:
. you can often see vid's of how to handle a gui interface;
it would be handy to instead have
a script that enhanced your gui:
it shows a balloon msg at what to click next;
and you can hit return to have it do one step at a time:
what it says you should be doing:
eg, it points to the menu,
hitting return opens the menu,
it points to a menu item,
hitting return launches the item ... .
. it can do this because
every gui view is represented as data structures,
so the demo app is reading as text
the same thing being shown to you graphically .
. it then finds what it expects,
and sends a balloon launch of the expected item .
. this way, if the app's interface changes,
then the demo can give up gracefully
when a search fails,
rather than showing you views of the app
that don't really exist .
1.24: news.adde/Apple`Popovers:
. the feature I had for adde recently
(integrated tutorials) [@] adde/integrated demo's
is partially supported by apple now,
and goes by the name Popovers .
. you can often see vid's of how to handle a gui interface;
it would be handy to instead have
a script that enhanced your gui:
it shows a balloon msg at what to click next;
and you can hit return to have it do one step at a time:
what it says you should be doing:
eg, it points to the menu,
hitting return opens the menu,
it points to a menu item,
hitting return launches the item ... .
. it can do this because
every gui view is represented as data structures,
so the demo app is reading as text
the same thing being shown to you graphically .
. it then finds what it expects,
and sends a balloon launch of the expected item .
. this way, if the app's interface changes,
then the demo can give up gracefully
when a search fails,
rather than showing you views of the app
that don't really exist .
1.24: news.adde/Apple`Popovers:
. the feature I had for adde recently
(integrated tutorials) [@] adde/integrated demo's
is partially supported by apple now,
and goes by the name Popovers .
"( AppKit framework now includes popovers,
a new unit of content that can be positioned relative to
other content on the screen.
Popovers automatically move whenever the
positioning view moves.
You can also design popovers that can be detached,
allowing them to become a separate window. )
which scripts are in what-size utf-8 codes
adde/utf-8/which codes are in how many bytes?
1.5: todo: [done]
. in utf-8, the number of bytes per code is incremental:
ascii uses 8bytes;
then how is it divided between 2..4 bytes
along what code pages? [1.31:
11-bits in 2 bytes, -- most euro or compact langs
16-bits in 3 bytes -- math & most other lang's
21-bits in 4 bytes --
In November 2003 UTF-8 was restricted to U+10FFFF,
in order to match the constraints of the
UTF-16 character encoding.
This removed the 5 and 6-byte sequences,
and about half the 4-byte sequences.]
1.6: web:
Bits Last code point Byte 1 Byte 2..4
7 7F 0xxxxxxx
11 07FF 110xxxxx 10xxxxxx
--. Latin letters with diacritics and characters from the
-- Greek, Cyrillic, Coptic, Armenian, Hebrew, Arabic, Syriac and Tāna alphabets
16 FFFF 1110xxxx 10xxxxxx *2
--. the rest of the Basic Multilingual Plane
-- (which contains virtually all characters in common use).
21 10,FFFF 11110xxx 10xxxxxx *3
--. less common CJK characters and various historic scripts.
1.31: web: where are the math symbols? in 3-bytes:
1.5: todo: [done]
. in utf-8, the number of bytes per code is incremental:
ascii uses 8bytes;
then how is it divided between 2..4 bytes
along what code pages? [1.31:
11-bits in 2 bytes, -- most euro or compact langs
16-bits in 3 bytes -- math & most other lang's
21-bits in 4 bytes --
In November 2003 UTF-8 was restricted to U+10FFFF,
in order to match the constraints of the
UTF-16 character encoding.
This removed the 5 and 6-byte sequences,
and about half the 4-byte sequences.]
1.6: web:
Bits Last code point Byte 1 Byte 2..4
7 7F 0xxxxxxx
11 07FF 110xxxxx 10xxxxxx
--. Latin letters with diacritics and characters from the
-- Greek, Cyrillic, Coptic, Armenian, Hebrew, Arabic, Syriac and Tāna alphabets
16 FFFF 1110xxxx 10xxxxxx *2
--. the rest of the Basic Multilingual Plane
-- (which contains virtually all characters in common use).
21 10,FFFF 11110xxx 10xxxxxx *3
--. less common CJK characters and various historic scripts.
1.31: web: where are the math symbols? in 3-bytes:
Mathematical Operators (U+2200–U+22FF)
Miscellaneous Mathematical Symbols-A (U+27C0–U+27EF)
Miscellaneous Mathematical Symbols-B (U+2980–U+29FF)
Supplemental Mathematical Operators (U+2A00–U+2AFF)
Letterlike Symbols (U+2100–U+214F)
Ceilings and floors in Miscellaneous technical (U+2308–U+230B)
Geometric Shapes (U+25A0–U+25FF)
Arrows in Miscellaneous Symbols and Arrows (U+2B30–U+2B4C)
Mathematical Alphanumeric Symbols (1D400–1D7FF)
translating Cocoa's obj'c to Ada's concurrency
1.24: adda/co/translating Cocoa's obj'c to Ada's concurrency:
. Hillegass's mac book has an inspiring section on concurrency .
summary:
the key to no race conditions is no indirect use of
shared modified variables;
anything done with the Cocoa libraries
should get exec'd as a msg sent to the main thread .
. adda needs a way to know when a function is
calling something that is not thread safe,
ie, not only can it not be allowed to modify non-locals,
it can't even call anyting that would modify a non-local
-- or even read a non-local if there's a chance that
some other thread might modify it .
. or else,
it can put mutexes around code doing the reading;
or, it can put shared globals in ada's protected var,
getting all requests by queue
and putting all outputs on a temp pointer provided by caller:
eg, "( this is one of the pointers on my mailbox,
it will be reserved for your response;
I will check it for non-nil until I find something ).
. Hillegass's mac book has an inspiring section on concurrency .
summary:
the key to no race conditions is no indirect use of
shared modified variables;
anything done with the Cocoa libraries
should get exec'd as a msg sent to the main thread .
. adda needs a way to know when a function is
calling something that is not thread safe,
ie, not only can it not be allowed to modify non-locals,
it can't even call anyting that would modify a non-local
-- or even read a non-local if there's a chance that
some other thread might modify it .
. or else,
it can put mutexes around code doing the reading;
or, it can put shared globals in ada's protected var,
getting all requests by queue
and putting all outputs on a temp pointer provided by caller:
eg, "( this is one of the pointers on my mailbox,
it will be reserved for your response;
I will check it for non-nil until I find something ).
Labels:
ada,
adda,
concurrency,
dev.cocoa
alloc-init pattern's rationale
1.23: sci,bk.adda/lang"obj'c/alloc-init pattern's rationale:
. in {Buck, Yacktman}`Cocoa Design Patterns
they explain the rational for separating init from alloc;
eg, x`= NSString`alloc`init .
. alloc can be a class function because
the mem requirements are known from
the interface ivars list defined by
self and self's superclasses .
. alloc works something like malloc,
only it is accepting a list of types
and converting them into the bytes count
that the malloc needs .
. my first reaction to this convention was:
how would you know what to allocate
until you see what there is to init?
these functions should indeed be separate;
but, the init should be calling the alloc,
rather than init being handed alloc's result by parameter .
. one continuing important reason for this convention
is communicating to client who it is that should be
doing the retains:
. the convention is that convenience methods are
using your autorelease pool .
. using the alloc init is your sign that
you own it (you need to auto/release it yourself )
. other than that, I've seen no intrinsic need for it;
... but, how does inheritance complicate things?
. it looks like the main reason is legacy code:
the Cocoa library can't maintain backward compatibility
unless you follow this convention .
. the main reason alloc was a class method,
was that init should be an instance method
but alloc (the source of the instance)
would have to be from a class method
because instance methods work on instances,
so the alloc couldn't be an instance method .
. I'm not sure whether {Buck, Yacktman} said that;
however, some oop evangelist did say that,
and I'd like to show next,
why I don't think it's true .
[1.31: 1.23:
. the usual oop idioms very much depend on
the root object being a pointer to heap node;
-- where that pointer that is the same size
across all objects --
and that pointer exists even before alloc is called .
. what the object really needs in order to have
access to some instance var's,
is to belong to some specific class;
and, it could get this either by
sending an init msg to the specific class it wants
or by letting the init's param decide on a class,
based upon the type of initial value assigned
(for example, when the compiler gets a value literal,
it can infer a type class from that:
"(abc) is a string
123 is a number
(1,2,3) is an array of number
(1, "(abc)) is a record in (number, string).
) . init figures out what it needs,
and then calls an alloc to help with that .
. if the client has a preference for some alloc technique
that could be a param of the init,
initWith (source, allocWith: style ) .]
. in {Buck, Yacktman}`Cocoa Design Patterns
they explain the rational for separating init from alloc;
eg, x`= NSString`alloc`init .
. alloc can be a class function because
the mem requirements are known from
the interface ivars list defined by
self and self's superclasses .
. alloc works something like malloc,
only it is accepting a list of types
and converting them into the bytes count
that the malloc needs .
. my first reaction to this convention was:
how would you know what to allocate
until you see what there is to init?
these functions should indeed be separate;
but, the init should be calling the alloc,
rather than init being handed alloc's result by parameter .
. one continuing important reason for this convention
is communicating to client who it is that should be
doing the retains:
. the convention is that convenience methods are
using your autorelease pool .
. using the alloc init is your sign that
you own it (you need to auto/release it yourself )
. other than that, I've seen no intrinsic need for it;
... but, how does inheritance complicate things?
. it looks like the main reason is legacy code:
the Cocoa library can't maintain backward compatibility
unless you follow this convention .
. the main reason alloc was a class method,
was that init should be an instance method
but alloc (the source of the instance)
would have to be from a class method
because instance methods work on instances,
so the alloc couldn't be an instance method .
. I'm not sure whether {Buck, Yacktman} said that;
however, some oop evangelist did say that,
and I'd like to show next,
why I don't think it's true .
[1.31: 1.23:
. the usual oop idioms very much depend on
the root object being a pointer to heap node;
-- where that pointer that is the same size
across all objects --
and that pointer exists even before alloc is called .
. what the object really needs in order to have
access to some instance var's,
is to belong to some specific class;
and, it could get this either by
sending an init msg to the specific class it wants
or by letting the init's param decide on a class,
based upon the type of initial value assigned
(for example, when the compiler gets a value literal,
it can infer a type class from that:
"(abc) is a string
123 is a number
(1,2,3) is an array of number
(1, "(abc)) is a record in (number, string).
) . init figures out what it needs,
and then calls an alloc to help with that .
. if the client has a preference for some alloc technique
that could be a param of the init,
initWith (source, allocWith: style ) .]
Labels:
adda,
class cluster,
design patterns,
dev.obj'c,
oop,
type,
type class
a fraction calculator's interface without over.key
1.22: adde/math/handling fractions:
. the Kochan`Fractions Calculator has an over.key,
for allowing a fraction to be entered without eval'ing it;
another way to handle this
is to enter complex expressions:
nothing is eval'd until you hit enter,
so, expecting fractions, the only division happens when
there is the form a/b / c/d .
. also, the policy could be that
div's would be eval'd only when
they represent exact fractions:
eg, 2/5 is 2/5, while 1/2 is 0.5 [1.31:
that does present a problem with the base being decimal, 2*5
but the storage's base being binary?
you could have an exact fraction like 1/5 = 0.2 in base 10,
but that is a irrational number in base 2 .]
...
. even if it did eval each operator a.s.a.p.,
it could simply reduce and stay exact:
14/10 = 7/5 = (1+2/5).
. the Kochan`Fractions Calculator has an over.key,
for allowing a fraction to be entered without eval'ing it;
another way to handle this
is to enter complex expressions:
nothing is eval'd until you hit enter,
so, expecting fractions, the only division happens when
there is the form a/b / c/d .
. also, the policy could be that
div's would be eval'd only when
they represent exact fractions:
eg, 2/5 is 2/5, while 1/2 is 0.5 [1.31:
that does present a problem with the base being decimal, 2*5
but the storage's base being binary?
you could have an exact fraction like 1/5 = 0.2 in base 10,
but that is a irrational number in base 2 .]
...
. even if it did eval each operator a.s.a.p.,
it could simply reduce and stay exact:
14/10 = 7/5 = (1+2/5).
Objective-C Categories
1.20: adda/type/obj'c categories:
. Apple is using the obj'c Category for mvc separation;*
eg, string has many uses in a command-line interface,
so it exists in the core package
without any methods for drawing on a gui;
categories are then simply extending that string type,
instead of having sublclasses reuse that string type
in yet another type;
so just one class can exist yet with
relevant parts in different packages .
* see { Buck, Yacktman}`Cocoa Design Patterns
todo:
. isn't that use of categories needed only because
it's assuming something demanded by the current oop model?
. if your string wants to talk about gui-specific tricks
like font, or curve following,
that should be served by a drawing record
which then has a string as one of it's parts .
(ie, it's ok to have 2 diff'ing classes !)
--
that was a main point of the book"design patterns:
it was a critique of oop's use of subclassing;
and, that criticism can apply equally well to categorizing;
but, notice it does have a good purpose:
it allows separate compilation of extensions
without having to recompile the original interface
which would then require a recompile of
all the clients of that interface .
. but in this case, the category pattern is not needed,
the pattern to follow is this:
. the whole point of the mvc pattern is that
nearly all programming should be doable without having to
be aware of what your output device is .
. the same program I write for the command-line
should be apply without modification
to use by the gui-interfaced user .
. the runtime is supposed to have a default way of
visualizing your data structures graphically .
. the user is just another inout process
interacting with your process;
so, the gui should be handled by 2 generic packages:
it communicates with a concurrent process,
and then is also aware of 2-d or 3-d
placement preferences of datastruct's .
. so, how does adda let you define special effects
such as those specific to one style of gui?
eg, the curve-following text
needs a record (string, linedata),
and that record should have a particular name, say SL,
so then any var assigned the type SL
will be treated by the adda system as curve-following text
at least when dealing with the contexts
that are specified as customized by SL .
. the 2 primary contexts that work like that
are the user interface,
and the memory usage:
(persistent file, ram buffer, L1,2,3 cache).
. conversely,
when assigning an SL value to a native type,
then all gui-specific info would be dropped .
analysis of what it offers:
. the category has 2 use cases, depending on
whether you have the interface code,
or just have an interface document
that doesn't list the private ivars of the type .
. if you don't have the interface,
the diff' it makes seems purely syntactic:*
native functions can be stated oopishly: x`f();
and with categories you can start writing x`MYf() .
. that is offering more than just
adding a package whose input types are x`type:
the new package is being registered with the type,
so when I ask that type to apply a symbol named MYf,
the run-time engine is able to say it does .
. so, what is the equivalent to that
in lispy procedural (vs oop) programming?
. say the apply-operator is @,
I can then say ('f @ 'x) to mean f(x),
so that to apply dynamically any variable, X,
to any function, F,
I can write X`= 'x, F`= 'f, .... F @ X .
. it then looks to see if there exists a function f
that accepts x`type .
*: [1.31:
. even without affecting ivars,
the diff' it makes can be quite significant;
because, it can override methods that have
special systemic effects on the ivars,
and those effects will be missing .
. the oop syntax allows this:
x`f()`g()`h()
which means that x`f() returns an object x2
which, in turn, understands
what to do with g(), etc .
. so, the functional equivalent to x`f(...)`g(...)`h(...)
is h(g(f(x, ...), ... ), ...).
. that could mean the run-time is doing another check:
is there an f(x`type).y,
such that there is a function named g
that can accept y`type ?
. obj'c is not concerned with that though,
because once you assign a function to a particular type,
the run-time can quickly know to use
the function name f that is registered with that type .
. after that, it doesn't matter whether g can handle it;
because the object returned by x`type according to x`f
is offering no other choices .
. the reason obj'c does it this way
is for the other use case:
where the interface is known so then the
functions being added to x`type
need to register with x`type because
otherwise they won't be granted access to x`type's
private instance var's .
. this, then, is what obj'c categories uniquely do;
it's something like ada's child package feature .
. Apple is using the obj'c Category for mvc separation;*
eg, string has many uses in a command-line interface,
so it exists in the core package
without any methods for drawing on a gui;
categories are then simply extending that string type,
instead of having sublclasses reuse that string type
in yet another type;
so just one class can exist yet with
relevant parts in different packages .
* see { Buck, Yacktman}`Cocoa Design Patterns
todo:
. isn't that use of categories needed only because
it's assuming something demanded by the current oop model?
. if your string wants to talk about gui-specific tricks
like font, or curve following,
that should be served by a drawing record
which then has a string as one of it's parts .
(ie, it's ok to have 2 diff'ing classes !)
--
that was a main point of the book"design patterns:
it was a critique of oop's use of subclassing;
and, that criticism can apply equally well to categorizing;
but, notice it does have a good purpose:
it allows separate compilation of extensions
without having to recompile the original interface
which would then require a recompile of
all the clients of that interface .
. but in this case, the category pattern is not needed,
the pattern to follow is this:
. the whole point of the mvc pattern is that
nearly all programming should be doable without having to
be aware of what your output device is .
. the same program I write for the command-line
should be apply without modification
to use by the gui-interfaced user .
. the runtime is supposed to have a default way of
visualizing your data structures graphically .
. the user is just another inout process
interacting with your process;
so, the gui should be handled by 2 generic packages:
it communicates with a concurrent process,
and then is also aware of 2-d or 3-d
placement preferences of datastruct's .
. so, how does adda let you define special effects
such as those specific to one style of gui?
eg, the curve-following text
needs a record (string, linedata),
and that record should have a particular name, say SL,
so then any var assigned the type SL
will be treated by the adda system as curve-following text
at least when dealing with the contexts
that are specified as customized by SL .
. the 2 primary contexts that work like that
are the user interface,
and the memory usage:
(persistent file, ram buffer, L1,2,3 cache).
. conversely,
when assigning an SL value to a native type,
then all gui-specific info would be dropped .
analysis of what it offers:
. the category has 2 use cases, depending on
whether you have the interface code,
or just have an interface document
that doesn't list the private ivars of the type .
. if you don't have the interface,
the diff' it makes seems purely syntactic:*
native functions can be stated oopishly: x`f();
and with categories you can start writing x`MYf() .
. that is offering more than just
adding a package whose input types are x`type:
the new package is being registered with the type,
so when I ask that type to apply a symbol named MYf,
the run-time engine is able to say it does .
. so, what is the equivalent to that
in lispy procedural (vs oop) programming?
. say the apply-operator is @,
I can then say ('f @ 'x) to mean f(x),
so that to apply dynamically any variable, X,
to any function, F,
I can write X`= 'x, F`= 'f, .... F @ X .
. it then looks to see if there exists a function f
that accepts x`type .
*: [1.31:
. even without affecting ivars,
the diff' it makes can be quite significant;
because, it can override methods that have
special systemic effects on the ivars,
and those effects will be missing .
. the oop syntax allows this:
x`f()`g()`h()
which means that x`f() returns an object x2
which, in turn, understands
what to do with g(), etc .
. so, the functional equivalent to x`f(...)`g(...)`h(...)
is h(g(f(x, ...), ... ), ...).
. that could mean the run-time is doing another check:
is there an f(x`type).y,
such that there is a function named g
that can accept y`type ?
. obj'c is not concerned with that though,
because once you assign a function to a particular type,
the run-time can quickly know to use
the function name f that is registered with that type .
. after that, it doesn't matter whether g can handle it;
because the object returned by x`type according to x`f
is offering no other choices .
. the reason obj'c does it this way
is for the other use case:
where the interface is known so then the
functions being added to x`type
need to register with x`type because
otherwise they won't be granted access to x`type's
private instance var's .
. this, then, is what obj'c categories uniquely do;
it's something like ada's child package feature .
large trees composed of byte-ptr trees
1.8: adda/mem'mgt/
large trees composed of byte-ptr trees:
. part of a space-saving obssession has been
finding how to make large trees be composed of
small trees that can use byte-sized pointers .
. the large tree is just like the local heap space:
a function activation record is given one segment
in which to store local data and param's;
after that fills up, it's turned into rib of a backbone segment:
(an array of c pointers to other segs).
. the way this is arranged should be such that
we can refer to the rib segs as indexes of the base seg,
. if all those fill up, then the last seg is the next size up:
. say the backbone hold 10ribs of size 10,
then the last rib is 10x10 size.
...
. isn't this supposed to be building the same way numbers do?
after the backbone fills up, it needs to be extended from above;
ie, replace the seg tree with a new backbone seg,
and then make the full backbone seg
a child of the new backbone seg:
====
|
====
| | | | | .
1.23: adda/type"tree/packing smaller trees:
. you can build a tree in large array
and if detecting under 255,
do a straight copy to small: for 1..256: copy word to byte
because the same links apply using the same structure
only smaller pointers .
large trees composed of byte-ptr trees:
. part of a space-saving obssession has been
finding how to make large trees be composed of
small trees that can use byte-sized pointers .
. the large tree is just like the local heap space:
a function activation record is given one segment
in which to store local data and param's;
after that fills up, it's turned into rib of a backbone segment:
(an array of c pointers to other segs).
. the way this is arranged should be such that
we can refer to the rib segs as indexes of the base seg,
. if all those fill up, then the last seg is the next size up:
. say the backbone hold 10ribs of size 10,
then the last rib is 10x10 size.
...
. isn't this supposed to be building the same way numbers do?
after the backbone fills up, it needs to be extended from above;
ie, replace the seg tree with a new backbone seg,
and then make the full backbone seg
a child of the new backbone seg:
====
|
====
| | | | | .
1.23: adda/type"tree/packing smaller trees:
. you can build a tree in large array
and if detecting under 255,
do a straight copy to small: for 1..256: copy word to byte
because the same links apply using the same structure
only smaller pointers .
wild vs proper goto's vs informal looping
1.6: adda/cstr/goto:
. if goto's are jumping high in same the block
the place they jump to need only be typed .loop,
but wild jumps need to be typed .<<>>
. when used at the end to break from a nested cstr,
the goto is a clean jump to bottom,
these are typed .exit? [1.31:
no:
. this is the proper use of goto;
so, it doesn't need a special type,
but every thing should have a type,
and the default type for labels could be .label .]
. to enter wrapup.label
use the syntax (enter wrapup) ? [1.31:
yes .]
. don't use the syntax (exit);
because, it may not be to exit self*
and (exit (current enclosure)) should be reserved for
situations that actually involve
jumping out of some enclosing container .
*:
. the other exits are {main, parent, thread}
as well as named cstr's {case, loop }.
. at each cstr (any structure that may contain stmts)
there can be a wrapup section named [on exit];
on().proc can also concurrently check
any number of conditions that implicitely
call the given responder routine when the guard is true . [1.31:
eg, on mem-out: (save work; log error) .]
. if goto's are jumping high in same the block
the place they jump to need only be typed .loop,
but wild jumps need to be typed .<<>>
. when used at the end to break from a nested cstr,
the goto is a clean jump to bottom,
these are typed .exit? [1.31:
no:
. this is the proper use of goto;
so, it doesn't need a special type,
but every thing should have a type,
and the default type for labels could be .label .]
. to enter wrapup.label
use the syntax (enter wrapup) ? [1.31:
yes .]
. don't use the syntax (exit);
because, it may not be to exit self*
and (exit (current enclosure)) should be reserved for
situations that actually involve
jumping out of some enclosing container .
*:
. the other exits are {main, parent, thread}
as well as named cstr's {case, loop }.
. at each cstr (any structure that may contain stmts)
there can be a wrapup section named [on exit];
on().proc can also concurrently check
any number of conditions that implicitely
call the given responder routine when the guard is true . [1.31:
eg, on mem-out: (save work; log error) .]
Labels:
adda,
cstr,
enclosures,
goto
variable case ranges
1.5: adda/cstr/case/variable case ranges:
. if the cases can be variable expressions
how does that work? how useful is that?
it does seem to suit a parallel case,
which would entail this equivalence:
e? # a: ;;; # b: ;;; # c: ;;; #; <=>
eval'd in parallel:
{ e= a? (;;;)
, e= b? (;;;)
, e= c? (;;;)
}
. the general characteristic required for
a non-parallel case stmt
is that it select no more than one of the
alternative execution paths .
. one useful example of variable case ranges
is when the use of variables and simple arithmetic
still provide a partition of the codomain,
ie, none of the case ranges are overlapping;
eg,
here are examples of simply shifting
the location of the boundaries between
exec'path guard partitions:
reals from a..d can vary to effect the outcome
of the following case .
e ?
#[a...b): proc1;
#[b...c): proc2;
#[c...d]: proc3 #;
and likewise for these variable integer ranges:
{a..b}, {b+1..c}, {c+1..d} .
. another use of such arithmetic
would provide case-range restrictions,
so that a varying set of cases are going to
the {others, do-nothing} execution paths .
. if the cases can be variable expressions
how does that work? how useful is that?
it does seem to suit a parallel case,
which would entail this equivalence:
e? # a: ;;; # b: ;;; # c: ;;; #; <=>
eval'd in parallel:
{ e= a? (;;;)
, e= b? (;;;)
, e= c? (;;;)
}
. the general characteristic required for
a non-parallel case stmt
is that it select no more than one of the
alternative execution paths .
. one useful example of variable case ranges
is when the use of variables and simple arithmetic
still provide a partition of the codomain,
ie, none of the case ranges are overlapping;
eg,
here are examples of simply shifting
the location of the boundaries between
exec'path guard partitions:
reals from a..d can vary to effect the outcome
of the following case .
e ?
#[a...b): proc1;
#[b...c): proc2;
#[c...d]: proc3 #;
and likewise for these variable integer ranges:
{a..b}, {b+1..c}, {c+1..d} .
. another use of such arithmetic
would provide case-range restrictions,
so that a varying set of cases are going to
the {others, do-nothing} execution paths .
parsing unmatching opening characters
1.5: adda/parse/algorithm for parsing containers:
. there can be non-matching container parts,
because they can be surounded by complete containers,
eg, ( ... [ ...{} ),
. the recursive way is this:
find an opening to some container,
and then call the function that reads that container;
what else that function will need, though,
is knowing whether it was sent by
another container-reading function;
so, in the example above, ( ... [ ...{} ),
getParen is calling getBracket( ")" ),
so then getBracket knows it needs to be stopping for
both {")", "]"}, whichever come first .
. if getBracket returns nil,
then getParen will know that the "[" should be taken as
a character, not the beginning of a subtree .
. any 3rd possibility?
no, but it does involve recursive backtracking,
with multiple readers on a single stream: [1.31:
. both caller and called could
fail to find their closing match .
. then to not have to do work over again,
it should have some way remembering
whether a given opening character has a match .
. another needed dimension is being fault tolerant:
if the coder forgot a closing character,
then there should be other ways of parsing
that will be able to guess something is missing;
eg, a line has found an new function definition
in the middle of a function body,
it could guess that the body above is
missing a closing character .]
. there can be non-matching container parts,
because they can be surounded by complete containers,
eg, ( ... [ ...{} ),
. the recursive way is this:
find an opening to some container,
and then call the function that reads that container;
what else that function will need, though,
is knowing whether it was sent by
another container-reading function;
so, in the example above, ( ... [ ...{} ),
getParen is calling getBracket( ")" ),
so then getBracket knows it needs to be stopping for
both {")", "]"}, whichever come first .
. if getBracket returns nil,
then getParen will know that the "[" should be taken as
a character, not the beginning of a subtree .
. any 3rd possibility?
no, but it does involve recursive backtracking,
with multiple readers on a single stream: [1.31:
. both caller and called could
fail to find their closing match .
. then to not have to do work over again,
it should have some way remembering
whether a given opening character has a match .
. another needed dimension is being fault tolerant:
if the coder forgot a closing character,
then there should be other ways of parsing
that will be able to guess something is missing;
eg, a line has found an new function definition
in the middle of a function body,
it could guess that the body above is
missing a closing character .]
Labels:
adda,
enclosures,
parse
inout-mode parameters
1.4: adda/syntax/{inout, out}-mode parameters:
. {inout, out}-mode parameters are special because
they create sideaffects .
[1.6:
. anyone coming from any other language
will be assuming that if you pass a pointer
then it means you get to modify
anything accessable by that pointer;
-- that is the whole point of pointers,
unless their targets are typed as being read-only mode;
however,
other languages have created a lot of bugs too,
so we really should carefully reconsider
designing our functions to be functional by default .
1.7:
. the usual understanding of aParam typed as
pointer to int is read-only pointer to inout int;
whereas, what we are assuming here is
read-only pointer to read-only int .
. the usual understanding of an
inout param typed as pointer to int is
inout pointer to inout int;
whereas, what we are assuming here is
inout pointer to read-only int .]
. the Ada goto label was chosen as notation that alarms,
and that's why I had chosen it for out-moding params;
the param x, a pointer to int,
out-moding on both the pointer and the int; [1.6:
however, something similar and easier to read is (^);
will it be confused with the power operator?
if it's placed at the back of the typemark,
then it clearly gives a context to reader and parser .]
. the most elegant way to define inout mode
is to unify it with its implied activity: inititialization .
. param's can specify default init values,
and if that init is the param' being defined,
that would imply inout mode
while doing something else essential . [1.6:
. however,
it seems counter to the intended model,
because defaults are supposed to tell you
what happens when you fail to supply the actual param,
implying that it's optional,
by contrast, what we're trying to say is:
not only is the param' instantiation not optional,
but the actual param's initial value is not optional either;
so, another idea is to precede the (out)-symbol
with an (in)-symbol such as (&);
since the default is in-mode,
and t^ means t is out-mode,
so t&^ would say t is in-mode & out-mode .
. if that seems like a stretch, then how about t'^ ?
the apostrophe seems like an arrow pointing down,
while the caret is arrow pointing up,
hence an iconic representation of inout;
and being on the back side of types,
it would fit in with the proposed typemark for
rom (read-only mem): t! .]-1.6
. when types contain types,
as in /.int (the type"pointer to int)
we need a notation to specify
which of those types can be modified;
therefore we can not
simply apply the notation to the parameter name,
as is done in other languages .
[1.7:
. we can provide that as an option though;
eg # inout aParam/.int!
--. this provides read-write access to
a pointer to a read-only int
(same as our aParam/'^.int);
eg # inout aParam/!.int
-- read-only access to a pointer to a read&writable int
(same as aParam/.int'^).]
[1.6:
. notice that, among container types such as
/.int (a pointer.type containing the int.type)
if you don't need the value of a param
(and are thus giving it the attribute out-mode),
you certainly don't need the values of any type within;
eg, /^.int'^ wouldn't make sense because
how can there be a value to get from the int
when there no value expected from
the pointer that is needed to access the int?
. if something like "(/^.int'^ )
could never make sense to some users anyway,
they should be allowed to use simple english too:
{out, inout } -- copy is the default .
. inout-mode could be understood to be
a property possessed by a type,
hence the use of the possessive operator:
/'^.int^ becomes /`inout.int`out (read:
pointer's inout to int's out ).
. another idea is that
{out, inout} would be functions over types,
so instead of needing a possessive operator,
you could simply use a space:
x/'^.int^ becomes x.inout /.out int .
. in this case, {inout, out} need to be reserved words?
we could allow renaming them,
eg, {o, io} or {wo, rw} might be popular .]-1.6
[1.6:
. by letting {out, inout} be a function,
it would also make sense to do it Ada's way:
letting the inout apply to the param itself,
instead of applying to each of the param's nested types;
eg,
inout x/.int -- just give me inout everything!
. why do you suppose Ada doesn't facilitate
applying {inout, out} to each of the param's
nested types?
[1.7: besides the fact that it's param's can
only trivially be container types
(you need to use a single type name
or a pointer to typename)]
. perhaps they are mostly concerned with
a transaction model:
this is where the implementation of out-mode
has the option of either using a reference,
or else doing a copy-in then copy-out .
. doing it my way could save much copying,
because suppose you have a pointer to a huge tree;
if all you want to do is modify the pointer,
then the copy-in©-out system
doesn't have to copy that huge tree for you! ]-1.6
1.7: web: ada parameters:
. Ada's rationale for not supporting pass-by-reference:
{. parameter passing by reference for access types
is not expected by most algorithms and will result in
those algorithms being incorrect .}
. access types are already unique in that the programmer is
permitted explicitly to manipulate references and construct aliases:
This is the purpose of access types,
and programmers using such types are asserting that
they wish to take control of all references and aliases.
Accordingly, the parameter passing should not generate
extra references and aliases of which the programmer is unaware;
therefore, all parameter passing for access types
should be by copy.
A final problem with parameter passing by reference
is that this mechanism will be almost impossible to achieve
(or at least, very costly) on distributed systems
and when dealing with systems having multiple address spaces.
--
. but the 2012 version does support them .
ada parameters/syntax:
2005 parameter_specification ::=
defining_identifier_list : mode [null_exclusion]
subtype_mark [:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
2012 parameter_specification ::=
defining_identifier_list : [aliased] mode [null_exclusion]
subtype_mark [:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
access_definition ::=
[null_exclusion] access [constant] subtype_mark
| [null_exclusion] access [protected]
procedure parameter_profile
| [null_exclusion] access [protected]
function parameter_and_result_profile access subtype_mark
. {inout, out}-mode parameters are special because
they create sideaffects .
[1.6:
. anyone coming from any other language
will be assuming that if you pass a pointer
then it means you get to modify
anything accessable by that pointer;
-- that is the whole point of pointers,
unless their targets are typed as being read-only mode;
however,
other languages have created a lot of bugs too,
so we really should carefully reconsider
designing our functions to be functional by default .
1.7:
. the usual understanding of aParam typed as
pointer to int is read-only pointer to inout int;
whereas, what we are assuming here is
read-only pointer to read-only int .
. the usual understanding of an
inout param typed as pointer to int is
inout pointer to inout int;
whereas, what we are assuming here is
inout pointer to read-only int .]
. the Ada goto label was chosen as notation that alarms,
and that's why I had chosen it for out-moding params;
eg, x<</.int>> would be used for havingthe param x, a pointer to int,
out-moding on both the pointer and the int; [1.6:
however, something similar and easier to read is (^);
will it be confused with the power operator?
if it's placed at the back of the typemark,
then it clearly gives a context to reader and parser .]
. the most elegant way to define inout mode
is to unify it with its implied activity: inititialization .
. param's can specify default init values,
and if that init is the param' being defined,
that would imply inout mode
while doing something else essential . [1.6:
. however,
it seems counter to the intended model,
because defaults are supposed to tell you
what happens when you fail to supply the actual param,
implying that it's optional,
by contrast, what we're trying to say is:
not only is the param' instantiation not optional,
but the actual param's initial value is not optional either;
so, another idea is to precede the (out)-symbol
with an (in)-symbol such as (&);
since the default is in-mode,
and t^ means t is out-mode,
so t&^ would say t is in-mode & out-mode .
. if that seems like a stretch, then how about t'^ ?
the apostrophe seems like an arrow pointing down,
while the caret is arrow pointing up,
hence an iconic representation of inout;
and being on the back side of types,
it would fit in with the proposed typemark for
rom (read-only mem): t! .]-1.6
. when types contain types,
as in /.int (the type"pointer to int)
we need a notation to specify
which of those types can be modified;
therefore we can not
simply apply the notation to the parameter name,
as is done in other languages .
[1.7:
. we can provide that as an option though;
eg # inout aParam/.int!
--. this provides read-write access to
a pointer to a read-only int
(same as our aParam/'^.int);
eg # inout aParam/!.int
-- read-only access to a pointer to a read&writable int
(same as aParam/.int'^).]
[1.6:
. notice that, among container types such as
/.int (a pointer.type containing the int.type)
if you don't need the value of a param
(and are thus giving it the attribute out-mode),
you certainly don't need the values of any type within;
eg, /^.int'^ wouldn't make sense because
how can there be a value to get from the int
when there no value expected from
the pointer that is needed to access the int?
. if something like "(/^.int'^ )
could never make sense to some users anyway,
they should be allowed to use simple english too:
{out, inout } -- copy is the default .
. inout-mode could be understood to be
a property possessed by a type,
hence the use of the possessive operator:
/'^.int^ becomes /`inout.int`out (read:
pointer's inout to int's out ).
. another idea is that
{out, inout} would be functions over types,
so instead of needing a possessive operator,
you could simply use a space:
x/'^.int^ becomes x.inout /.out int .
. in this case, {inout, out} need to be reserved words?
we could allow renaming them,
eg, {o, io} or {wo, rw} might be popular .]-1.6
[1.6:
. by letting {out, inout} be a function,
it would also make sense to do it Ada's way:
letting the inout apply to the param itself,
instead of applying to each of the param's nested types;
eg,
inout x/.int -- just give me inout everything!
. why do you suppose Ada doesn't facilitate
applying {inout, out} to each of the param's
nested types?
[1.7: besides the fact that it's param's can
only trivially be container types
(you need to use a single type name
or a pointer to typename)]
. perhaps they are mostly concerned with
a transaction model:
this is where the implementation of out-mode
has the option of either using a reference,
or else doing a copy-in then copy-out .
. doing it my way could save much copying,
because suppose you have a pointer to a huge tree;
if all you want to do is modify the pointer,
then the copy-in©-out system
doesn't have to copy that huge tree for you! ]-1.6
1.7: web: ada parameters:
. Ada's rationale for not supporting pass-by-reference:
{. parameter passing by reference for access types
is not expected by most algorithms and will result in
those algorithms being incorrect .}
. access types are already unique in that the programmer is
permitted explicitly to manipulate references and construct aliases:
This is the purpose of access types,
and programmers using such types are asserting that
they wish to take control of all references and aliases.
Accordingly, the parameter passing should not generate
extra references and aliases of which the programmer is unaware;
therefore, all parameter passing for access types
should be by copy.
A final problem with parameter passing by reference
is that this mechanism will be almost impossible to achieve
(or at least, very costly) on distributed systems
and when dealing with systems having multiple address spaces.
--
. but the 2012 version does support them .
ada parameters/syntax:
2005 parameter_specification ::=
defining_identifier_list : mode [null_exclusion]
subtype_mark [:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
2012 parameter_specification ::=
defining_identifier_list : [aliased] mode [null_exclusion]
subtype_mark [:= default_expression]
| defining_identifier_list : access_definition
[:= default_expression]
access_definition ::=
[null_exclusion] access [constant] subtype_mark
| [null_exclusion] access [protected]
procedure parameter_profile
| [null_exclusion] access [protected]
function parameter_and_result_profile access subtype_mark
Labels:
1st-class functions,
adda,
syntax,
type
generic type vs container type
1.4: adda/type/{generic, container}-type def's:
. there is a syntax for parametric types generally,
with multiple params that include
both types and non-types ? yes:
[1.6:
. the parameterized type is a sort of generic;
so, there are 2 points at which it is instantiated:
once to define the concrete type,
and then again for each use of that concrete type
in defining an obj' instance .
. to distinguish these,
use the terms {generic, container}-type .
. the {array, pointer} are really containers;
on the way to defining more container types,
you can use a generic type
which then must be instantiated
before use by container obj's .
. a container type could accept a record type as its leaf;
then each of those record fields
could be instantiations of a generic-type
that could return a container-type .
. the generic-types should not need
separate instantiation:
[1.7: eg,
( myLeafType.type: gentype(init)
; x.myLeafType; )
can also be done as x.gentype(init) .]
. here's a combination of generic and container instantiations
in one term:
pointertype(inits for variant selection).myLeafType .
. arrays, pointers, and functions are container types;
how are new container types defined ?
. recall that pointers and arrays are
types of functions [expressing container types]
but, can new [container] types be
defined like functions without confusion ?
yes:
. a function where the arg is of type .type;
eg, pointer.type is defined as:
/(type).type;
this works with these rules:
(1) function args are not required to be paren'd,
(2) types are preceded by a dot:
/.txt = /(.txt).
. there is a syntax for parametric types generally,
with multiple params that include
both types and non-types ? yes:
[1.6:
. the parameterized type is a sort of generic;
so, there are 2 points at which it is instantiated:
once to define the concrete type,
and then again for each use of that concrete type
in defining an obj' instance .
. to distinguish these,
use the terms {generic, container}-type .
. the {array, pointer} are really containers;
on the way to defining more container types,
you can use a generic type
which then must be instantiated
before use by container obj's .
. a container type could accept a record type as its leaf;
then each of those record fields
could be instantiations of a generic-type
that could return a container-type .
. the generic-types should not need
separate instantiation:
[1.7: eg,
( myLeafType.type: gentype(init)
; x.myLeafType; )
can also be done as x.gentype(init) .]
. here's a combination of generic and container instantiations
in one term:
pointertype(inits for variant selection).myLeafType .
. arrays, pointers, and functions are container types;
how are new container types defined ?
. recall that pointers and arrays are
types of functions [expressing container types]
but, can new [container] types be
defined like functions without confusion ?
yes:
. a function where the arg is of type .type;
eg, pointer.type is defined as:
/(type).type;
this works with these rules:
(1) function args are not required to be paren'd,
(2) types are preceded by a dot:
/.txt = /(.txt).
Labels:
1st-class functions,
adda,
generics,
type
adda minimizes paretheses
1.3: adda/syntax/lists of algorithm literals:
. the comma-semicolon syntax for lists
( ,,, ; ,,,,, ; ,,, ) would be confused with
those of an algorithm literal,
( ,,,: ; ;;; ,,,:; ;;; )
unless the algorithm literal is parenthesized;
( ,,, ; ,,( ,,,: ; ;;; ,,,:; ;;; ), ; ,,, )
that should be a general requirement
with the exception that
a file already constitutes a parenthesis .
[1.6: (interactive mode is a type of streamed file;
and adding the paren's would supress execution
until the closing paren' was added) .]
. with that requirement in place,
I can feel more confident designing
subprogram calls without paren's
[@] adda/syntax/subprogram calls without paren's
adda/syntax/
subprogram calls without paren's
. one thing I was taught by lisp counter/zealotry
is that if a language is to have
any chance of being popular
it should go out of its way to
avoid excessive parentheses!
. any symbol that is declared as a function
and is found in a sequence of statements,
can use the form: f x,y,z;
instead of f(x,y,z) .
. if you have: f g x,y;
that should be parsed as f(g(x,y)) ?
at least according to the
nested-if rule:
(if * then if * then * else *)
-- that would be parsed
like so:
if * then (if * then * else *)
rather than:
if * then (if * then * ) else * .
. but what does that do for the rule about
lists requiring paren's when nested in lists?
[@] adda/syntax/lists of algorithm literals
. moot: a unary arg is not a list .
. the comma-semicolon syntax for lists
( ,,, ; ,,,,, ; ,,, ) would be confused with
those of an algorithm literal,
( ,,,: ; ;;; ,,,:; ;;; )
unless the algorithm literal is parenthesized;
( ,,, ; ,,( ,,,: ; ;;; ,,,:; ;;; ), ; ,,, )
that should be a general requirement
with the exception that
a file already constitutes a parenthesis .
[1.6: (interactive mode is a type of streamed file;
and adding the paren's would supress execution
until the closing paren' was added) .]
. with that requirement in place,
I can feel more confident designing
subprogram calls without paren's
[@] adda/syntax/subprogram calls without paren's
adda/syntax/
subprogram calls without paren's
. one thing I was taught by lisp counter/zealotry
is that if a language is to have
any chance of being popular
it should go out of its way to
avoid excessive parentheses!
. any symbol that is declared as a function
and is found in a sequence of statements,
can use the form: f x,y,z;
instead of f(x,y,z) .
. if you have: f g x,y;
that should be parsed as f(g(x,y)) ?
at least according to the
nested-if rule:
(if * then if * then * else *)
-- that would be parsed
like so:
if * then (if * then * else *)
rather than:
if * then (if * then * ) else * .
. but what does that do for the rule about
lists requiring paren's when nested in lists?
[@] adda/syntax/lists of algorithm literals
. moot: a unary arg is not a list .
Labels:
1st-class functions,
adda,
cstr,
syntax
adda's case stmt evolves
1.2: adda/cstr/case/
similar to goto labels not function points list:
[1.5: intro:
. the case stmt was seen to share the same structure as
that of the param'list, record'literal,
and the function points list:
( domain-elements,,,: codomain-element
, d,d,d,d: cod
) -- if a domain element is followed by a comma,
then it's part of a list of domain elements
all sharing the same codomain element .
. however,
the colon character is also used for identifying address labels:
( label,,,: ; ;;;
label:
...)
-- the c lang's fall-through case stmt has similar syntax
in that it's reusing label syntax * .
. the case doesn't need commas like the function points list;
because, it can work like other labels; [1.31:
(the case stmt does still use commas for the domain lists;
ie, for when multiple cases having the same target ).]
. the usual (;) vs (,) priority is exemplified by the matrix, eg:
( el, el, el,
; el, el, el,
; el, el, el ),
[1.31: this is contrast to the list of statement's
in which declaration stmt's use commas in the domain list:
( v1, v2, v3: shared-type
; v1, v2, v3: shared-type
; stmt; stmt; stmt
);]
. a case list (the list of control paths being offered)
has elements that include sequences (of stmt's);
so, we have to make sure that the context always tells us
which situation you're going into:
a list of lists, (as seen in a matrix) versus
a list of sequences .
. if a sequence of stmts is an element in matrix
it creates ambiguity if unparenthesized:
(,,,
; ,,, ;;; ,
; ,,,
) .
*: [1.31:
. actually, a key feature of c's case syntax,
is the case-prefixing used within the body-container of
switch ( expression ) body-container:
switch ( expression )
{ declaration stmts ;;; -- adda instead has inline decl's .
case a: -- the case label is like a stmt but terminated by (:);
case b: stmt; stmt; -- a's and b's target stmts .
default: stmt .
} .
. the adda case stmt differs from c's in that
it is like its other conditional stmt (the if):
truth ? stmt else stmt; -- the if-else;
truth ? #true: stmt; #false: stmt; #; -- the case .
. like c, however, adda tries to minimize syntax;
and, towards that end,
notice the cases wouldn't need paren's around them if
the final case keyword was followed by the (;);
conversely, the (#.) is not needed if
the case stmt or its body are in paren's;
however, always having a case-terminal at the end of case
might help syntax errors involving enclosures;
or else it could be thought of as a type of enclosure:
( ,,, ; ,,, ; ,,, . ,,, ; ,,, ; ,,, ) -- for the data
#a: s;s;s; #b: s;s;s; #; -- for the cases .
. if preferring english over symbols, (case) = (#):
truth ?
case true: stmt;
case false: stmt;
case; ]-1.31
1.2: adda/cstr/case/
supporting c's fall-through style:
. should the case like c's be called fallthru?
how could it be called jmp or goto?
it should include the usual syntax shared by
all conditional stmt's .
[... but that syntax is about to change:]
[@] adda/cstr/case/similar to goto labels not function points list
fallthru e ? (e, ,,, : s; s; s; e,,,: s;;; );
--
. the inside of a case stmt looks just like a stmt block .
. fallthru is a control function of 1 arg:
fallthru(case.stmt).stmt;
it expects its arg to be a case stmt .
1.5: inverting the default:
. a more intuitive use of the fallthru keyword
would be to have it used for
meaning just the opposite of the c lang's break stmt:
. when you wanted to fall-through,
then the fallthru stmt would be used to override
the default behavior .
1.5: minimize reserved words:
. instead of fallthru as a keyword
it might be better to reuse what we have,
such as (enter next),
-- "(next) doesn't have to be a reserved word,
because it's still local to the arg of function"enter --
or generalize it like this: [1.8:
enter case [some label within the case stmt] ].
adda/cstr/case/
only fallthru's need an exit stmt:
1.2:
. in a fallthru, the break is called exit,
just as in the loops,
when loops and case stmts are nested
you can specify where you want to exit to:
ie, "(exit loop) vs "(exit fallthru) .
. if it's a normal (non-fallthru) case stmt,
then there is no need for an exit stmt
so mentioning exit
would apply to a surrounding loop or fallthru .
1.5: not true:
. that's actually debatable;
because, a case could want to bail out early?;
conversely,
while an exit may be useful for some,
it could be inconvenient for many,
as it is very common have a case within a loop,
so if the case's use of exit could apply to itself
instead of the surrounding loop,
then that use of the exit stmt would have to specify
whether it referred to the {case stmt, loop stmt},
and the default target for an exit from a case stmt
would intuitively be exit case,
whereas in most cases the exit loop was desired;
then again,
it would be simpler, and more readable,
to have no default,
and then you could let coders have maximal freedom,
exiting anything from anywhere .
. furthermore,
even fall-through case stmts rarely do a fall-through;
they usually have more break stmt's than not;
so, the default behavior at the end of a case (case.stmt`branch)
should be (exit case) rather than (fallthru)
and if you mean otherwise, use an (enter next case).stmt
only at the end of the particular case
that needs to fall through .
1.2: adda/cstr/case/
supporting c's fall-through style:
. should the case like c's be called fallthru?
how could it be called jmp or goto?
it should include the usual syntax shared by
all conditional stmt's .
[... but that syntax is about to change:]
[@] adda/cstr/case/similar to goto labels not function points list
fallthru e ? (e, ,,, : s; s; s; e,,,: s;;; );
--
. the inside of a case stmt looks just like a stmt block .
. fallthru is a control function of 1 arg:
fallthru(case.stmt).stmt;
it expects its arg to be a case stmt .
1.5: inverting the default:
. a more intuitive use of the fallthru keyword
would be to have it used for
meaning just the opposite of the c lang's break stmt:
. when you wanted to fall-through,
then the fallthru stmt would be used to override
the default behavior .
1.5: minimize reserved words:
. instead of fallthru as a keyword
it might be better to reuse what we have,
such as (enter next),
-- "(next) doesn't have to be a reserved word,
because it's still local to the arg of function"enter --
or generalize it like this: [1.8:
enter case [some label within the case stmt] ].
adda/cstr/case/
the cases need not be literals:
1.2:
. whether the labels need to be const's,
being enums they eval to self,
so generally the case guard can always be eval'd;
you can also use expressions as literal cases
by quoting them, which supresses eval;
in that case,
the expr being cased should eval to etree;
because, a quoted expression is always an etree .
similar to goto labels not function points list:
[1.5: intro:
. the case stmt was seen to share the same structure as
that of the param'list, record'literal,
and the function points list:
( domain-elements,,,: codomain-element
, d,d,d,d: cod
) -- if a domain element is followed by a comma,
then it's part of a list of domain elements
all sharing the same codomain element .
. however,
the colon character is also used for identifying address labels:
( label,,,: ; ;;;
label:
...)
-- the c lang's fall-through case stmt has similar syntax
in that it's reusing label syntax * .
. the case doesn't need commas like the function points list;
because, it can work like other labels; [1.31:
(the case stmt does still use commas for the domain lists;
ie, for when multiple cases having the same target ).]
. the usual (;) vs (,) priority is exemplified by the matrix, eg:
( el, el, el,
; el, el, el,
; el, el, el ),
[1.31: this is contrast to the list of statement's
in which declaration stmt's use commas in the domain list:
( v1, v2, v3: shared-type
; v1, v2, v3: shared-type
; stmt; stmt; stmt
);]
. a case list (the list of control paths being offered)
has elements that include sequences (of stmt's);
so, we have to make sure that the context always tells us
which situation you're going into:
a list of lists, (as seen in a matrix) versus
a list of sequences .
. if a sequence of stmts is an element in matrix
it creates ambiguity if unparenthesized:
(,,,
; ,,, ;;; ,
; ,,,
) .
*: [1.31:
. actually, a key feature of c's case syntax,
is the case-prefixing used within the body-container of
switch ( expression ) body-container:
switch ( expression )
{ declaration stmts ;;; -- adda instead has inline decl's .
case a: -- the case label is like a stmt but terminated by (:);
case b: stmt; stmt; -- a's and b's target stmts .
default: stmt .
} .
. the adda case stmt differs from c's in that
it is like its other conditional stmt (the if):
truth ? stmt else stmt; -- the if-else;
truth ? #true: stmt; #false: stmt; #; -- the case .
. like c, however, adda tries to minimize syntax;
and, towards that end,
notice the cases wouldn't need paren's around them if
the final case keyword was followed by the (;);
conversely, the (#.) is not needed if
the case stmt or its body are in paren's;
however, always having a case-terminal at the end of case
might help syntax errors involving enclosures;
or else it could be thought of as a type of enclosure:
( ,,, ; ,,, ; ,,, . ,,, ; ,,, ; ,,, ) -- for the data
#a: s;s;s; #b: s;s;s; #; -- for the cases .
. if preferring english over symbols, (case) = (#):
truth ?
case true: stmt;
case false: stmt;
case; ]-1.31
1.2: adda/cstr/case/
supporting c's fall-through style:
. should the case like c's be called fallthru?
how could it be called jmp or goto?
it should include the usual syntax shared by
all conditional stmt's .
[... but that syntax is about to change:]
[@] adda/cstr/case/similar to goto labels not function points list
fallthru e ? (e, ,,, : s; s; s; e,,,: s;;; );
--
. the inside of a case stmt looks just like a stmt block .
. fallthru is a control function of 1 arg:
fallthru(case.stmt).stmt;
it expects its arg to be a case stmt .
1.5: inverting the default:
. a more intuitive use of the fallthru keyword
would be to have it used for
meaning just the opposite of the c lang's break stmt:
. when you wanted to fall-through,
then the fallthru stmt would be used to override
the default behavior .
1.5: minimize reserved words:
. instead of fallthru as a keyword
it might be better to reuse what we have,
such as (enter next),
-- "(next) doesn't have to be a reserved word,
because it's still local to the arg of function"enter --
or generalize it like this: [1.8:
enter case [some label within the case stmt] ].
adda/cstr/case/
only fallthru's need an exit stmt:
1.2:
. in a fallthru, the break is called exit,
just as in the loops,
when loops and case stmts are nested
you can specify where you want to exit to:
ie, "(exit loop) vs "(exit fallthru) .
. if it's a normal (non-fallthru) case stmt,
then there is no need for an exit stmt
so mentioning exit
would apply to a surrounding loop or fallthru .
1.5: not true:
. that's actually debatable;
because, a case could want to bail out early?;
conversely,
while an exit may be useful for some,
it could be inconvenient for many,
as it is very common have a case within a loop,
so if the case's use of exit could apply to itself
instead of the surrounding loop,
then that use of the exit stmt would have to specify
whether it referred to the {case stmt, loop stmt},
and the default target for an exit from a case stmt
would intuitively be exit case,
whereas in most cases the exit loop was desired;
then again,
it would be simpler, and more readable,
to have no default,
and then you could let coders have maximal freedom,
exiting anything from anywhere .
. furthermore,
even fall-through case stmts rarely do a fall-through;
they usually have more break stmt's than not;
so, the default behavior at the end of a case (case.stmt`branch)
should be (exit case) rather than (fallthru)
and if you mean otherwise, use an (enter next case).stmt
only at the end of the particular case
that needs to fall through .
1.2: adda/cstr/case/
supporting c's fall-through style:
. should the case like c's be called fallthru?
how could it be called jmp or goto?
it should include the usual syntax shared by
all conditional stmt's .
[... but that syntax is about to change:]
[@] adda/cstr/case/similar to goto labels not function points list
fallthru e ? (e, ,,, : s; s; s; e,,,: s;;; );
--
. the inside of a case stmt looks just like a stmt block .
. fallthru is a control function of 1 arg:
fallthru(case.stmt).stmt;
it expects its arg to be a case stmt .
1.5: inverting the default:
. a more intuitive use of the fallthru keyword
would be to have it used for
meaning just the opposite of the c lang's break stmt:
. when you wanted to fall-through,
then the fallthru stmt would be used to override
the default behavior .
1.5: minimize reserved words:
. instead of fallthru as a keyword
it might be better to reuse what we have,
such as (enter next),
-- "(next) doesn't have to be a reserved word,
because it's still local to the arg of function"enter --
or generalize it like this: [1.8:
enter case [some label within the case stmt] ].
adda/cstr/case/
the cases need not be literals:
1.2:
. whether the labels need to be const's,
being enums they eval to self,
so generally the case guard can always be eval'd;
you can also use expressions as literal cases
by quoting them, which supresses eval;
in that case,
the expr being cased should eval to etree;
because, a quoted expression is always an etree .
Labels:
adda,
case,
conditional,
cstr
Subscribe to:
Posts (Atom)
