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 .
2012-01-31
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)