auto conversion would be nice. for example, you should be able to tag a value as a "log return" and then print it in the form of "arithmetic return". note that this transformation is nonlinear, so "log return" is a "unit", adding one type of unit = multiplying another type.
and the units should themselves be sets or tuples of attribute tags, so that you can have "log inches" and write the code for "log<-->1" conversions and "inch<-->foot" conversions and then autoconverst "log inches<-->feet"
want a standard convention to pass keyword dicts of 'extra' information UP the call chain, info that will not be understood and will be ignored by most passers
multiappend
the Cycle library i wrote should be trivial in Oot, even though it's more list-oriented than graph-oriented
some neat python flow control: break continue next else(else can be applied to loops)
" The break statement, like in C, breaks out of the smallest enclosing for or while loop.
The continue statement, also borrowed from C, continues with the next iteration of the loop.
Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement. This is exemplified by the following loop, which searches for prime numbers: "
neat syntax for sending messages:
limitTicks.append = findEdgeDispersionWithMinimumReturn(cycle, self._b, edgeIdx)
that is, just reuse the single graph edge traversal/__setitem__ syntax
---
i just fixed an annoying bug of the form:
def handleMessage(self, key, newValues):
blah = sum([self.storage[key].get('quantity',0) for key in self.openOrders[name]['keys']])
...
self.storage[key] = newValuesdo you see it? 'key' is being bound in the for loop in the 'blah' line, so the values will be stored in the wrong key
--- this common pattern should be supported cleanly:
somehash.get(somehashkey, []).append(some_item_to_go_into_the_list_associated_with_that_hash_key)
(perhaps just use defaultdict?)
or even: thelist = somehash.get(somehashkey, []) thelist.append(some_item_to_go_into_the_list_associated_with_that_hash_key) somehash[somehashkey] = thelist
to notify the dict-like object that something has changed (in case its a persistent store, for example)
also this pattern:
if somekey in somedict: do_something_using somedict[somekey]
mb this can be subsumed into a python-like "with"?
list comprehension conditions should short-circutly evaluate and short-circut the evaluation of the main body (i think python does this)
docstrings are awesome
ipython's '?' is awesome
generator comprehensions
too bad you can't mix numpy arrays and comprehensions
just as the columns in a dataframe can be referred to by name or by an integer index, oot edges can have multiple labels, each of which lives in a different universe
python's for..else
---
why not let Python's default keyword argument syntax be used in expressions, too?
---
topic maps
http://www.ontopia.net/topicmaps/materials/tao.html
" Each topic that participates in an association plays a role in that association called the association role. In the case of the relationship “Puccini was born in Lucca”, expressed by the association between Puccini and Lucca, those roles might be “person” and “place”; for “Tosca was composed by Puccini” they might be “opera” and “composer”. It will come as no surprise now to learn that association roles can also be typed and that the type of an association role is also a topic!
Unlike relations in mathematics, associations are inherently multidirectional. In topic maps it doesn't make sense to say that A is related to B but that B isn't related to A: If A is related to B, then B must, by definition, be related to A. Given this fact, the notion of association roles assumes even greater importance. It is not enough to know that Puccini and Verdi participate in an “influenced-by” association; we need to know who was influenced by whom, i.e. who played the role of “influencer” and who played the role of “influencee”.
This is another way of warning against believing that the names assigned to association types (such as “was influenced by”) imply any kind of directionality. They do not! This particular association type could equally well (under the appropriate circumstances) be characterized by the name “influenced” (as in “Verdi influenced Puccini”). (See section 3.4.3. for an example (involving Tosca and Rome) of how the scope feature might be used to make this happen in practice.) "
" Secondly, associations are completely different in structure from RDF statements. They have roles representing the involvement of each topic in the association, and they go both ways. That is, in topic maps saying that I am employed by Ontopia is the same statement as saying Ontopia employs me. This means that the issue of whether to make my employment a property of Ontopia or of me is a non-issue in topic maps; it will always be both. "
" To summarize, a statement in RDF can be a name, an occurrence, or an association in topic maps. Names compare easily to RDF: they are RDF statements where the object is a literal and where the property has name semantics. The remaining RDF statements where the object is a literal are occurrences. However, RDF statements where the object is another resource are either occurrences or associations, depending on the semantics of the statement. If they are associations role types must be supplied. In addition to this comes the cases where in a topic map the association has more than two roles, in which case an intermediate RDF resource must be created. "
" In RDF there are three kinds of nodes:
literals (which we have already discussed).
URI nodes. A URI is just a node that has a URI label on it, where the URI identifies the resource represented by the node. Since the URI directly identifies the resource represented by a node, RDF assumes that nodes with the same URI represent the same resource.
blank nodes. These nodes are called blank, as they have no URI label. (Two examples can be seen in the RDF diagram example in section 2.2..) For blank nodes the only way to discover which resource they represent is to look at the statements made about them. RDF itself provides no standardized way to identify which blank nodes represent the same resources, although higher-level vocabularies like OWL do. (More about this in section 4.1.2..)"
" Let's say we use the URI http://www.ontopia.net/ to identify a thing. Now, what does this actually identify? The information resource we get by resolving the URI? Or the thing described by that information resource? In practice, one finds that URIs are being used in both ways.
Topic maps distinguish these two cases, so that when assigning a URI to a topic as an identifier, the URI can be considered to be a subject address or a subject identifier. In the first case, the subject identified is the resource. In the second case it is whatever is described by the resource. In RDF, however, this distinction does not exist, and given a URI node there is no way to tell a priori which of the two ways the URI should be interpreted.
This is actually quite a thorny problem for interoperability between topic maps and RDF, and is also indicative of differences in the thinking behind the two. RDF practitioners would say that RDF models consist of statements and resources, ignoring the fact that the resources are not really part of the RDF model, but are represented by RDF nodes. In RDF, the distinction between the RDF model and the world it represents is not given much emphasis, whereas in topic maps this distinction premeates the whole model. "
also reification and levels; topic maps are for making a back-of-the-book index of hypertext, and talk about "occurences" of the topic in the referenced hypertext; this should be generalized into a single data model
in fact, should have a separate document for properties of the graph data model:
nLSD RDF OWL RDF Schema
chu spaces
some predefined relations (see also OWL): name inverse type isa subclass (implies?)
these can all have a qualifier 'typically' or 'logically', with 'typically' being the default
XDI
topic maps unify provenance and qualification as 'scope':
" Qualification
Sometimes one wishes to qualify assertions made about things in order to record which authority claims they are true, what the source of the assertion is, or in what context the assertion is true.
In topic maps there is a built-in feature for this: scope. When an assertion is made in a topic map (in the form of a name, an occurrence, or an association) a scope is always attached to it. The default scope is the unconstrained scope, which means that there is no known limit to the validity of the assertion. Topics can be added to the scope to restrict under what circumstances it is considered to be true. Some examples are shown below.
Topic maps are called "topic maps" in English, but in Norwegian they are called "emnekart". This is best represented by creating a single topic with two names, one in the scope English, and one in the scope Norwegian.
There is a topic map with topics for each officially identified issue with the topic map standard, and these have occurrences of type "opinion", which gives an opinion about the issue. Each opinion is scoped with a topic representing the person who held the opinion.
There is a group of people who believe that Francis Bacon wrote Shakespeare's plays, and this might be represented by adding extra authorship associations between the plays and Francis Bacon, and scoping it with a topic representing this group of people.
In RDF there is no built-in feature for this, except that literals may have a language identifier attached to them, which is a kind of qualification. (A language identifier is a string conforming to RFC 3066[RFC 3066], such as en-uk or pt-br.) However, it is possible to achieve this through reification, since this turns the statement into a node about which statements (including qualifying ones) may be made. On the other hand, reification in RDF is, as we noted above, rather awkward in practical use.
Again it should be added that not having direct support for this makes RDF more light-weight, but this is a feature that is quite often needed, especially for internationalization, but also for tracking the sources of assertions. It should be added that although RDF itself does not support this, support for it can be built into individual applications by creating extra resources for assertions.
The key problem here is that statements in RDF have no identity, which means that it is impossible to make resources that represent them (without changing the statements) and since the model does not directly support qualification support for qualification cannot be added through reification. This is one of the most fundamental differences between topic maps and RDF, and one that has so far frustrated all attempts to model topic maps in RDF in a natural way. "
---
" 8. Addressable and non-addressable subjects
The subject of every assertion (or statement) in an RDF model is a resource, identified by a URI. The subject of every assertion in a topic map is a topic, representing a subject, which may be addressable or non-addressable. Addressable subjects are identified by their URIs (as in RDF); non-addressable subjects are identified by the URIs of (one or more) subject indicators. This important distinction is not present in RDF. "
" /* topic types */
[person = "PERSON" @"http://taoriver.net/nLSD/person/"] [parent ; person = "Parent"] [child ; person = "Child"] [childOf : Hidden = "is child of"] /* template provides visualization direction */ childOf([child] : From, [parent] : To ) / Template [sakura : child = "Sakura Kimbro-Juliao" ] childOf(sakura : child, [kitty : parent = "Amber Straub" ] : parent ) childOf(sakura : child, [lion : parent = "Lion Kimbro"] : parent )"
the open annotation spec ( http://www.openannotation.org/ ) has three parts to every annotation (three RDF nodes), the annotation itself, the annotation body. Optionally, the target node itself points to two nodes, the actual target, and another (potentially freeform) node which defines the part of the target which is being addressed.
--- should study this language to learn to be faster:
Topic: Julia: A Fast Dynamic Language For Technical Computing
Speaker: Jeff Bezanson MIT
About the talk:
Julia is a general-purpose, high-level, dynamic language, designed from the start to take advantage of techniques for executing dynamic languages at statically-compiled language speeds. As a result the language has a more powerful type system, and generally provides better type information to the compiler.
Julia is especially good at running MATLAB and R-style programs. Given its level of performance, we envision a new era of technical computing where libraries can be developed in a high-level language instead of C or FORTRAN. We have also experimented with cloud API integration, and begun to develop a web-based, language-neutral platform for visualization and collaboration. The ultimate goal is to make cloud-based supercomputing as easy and accessible as Google Docs.
let's say you had personalized (perspectivized) reputation graphs -- each perspective is essentially a function that maps each node (or some subsets of nodes) to a floating point number (or, 'labels each node with a floating point number')? would oot express this as a "graph overlay"? or another graph that could be 'merged in'? or a function? or all three, with conversion operators?
also, category theory diagrams (maps on the nodes AND edges)
inversed, uniques/injective&surjective as a core feature:
No programming language to date (except possibly haskell) understands whether one function is intended to be the inverse of another, whether items in a list are unique, etc. This would allow clean syntax for things like inverse (^-1 even, or just ^-) and some amount of automated reasoning and type inference.
Colored exceptions nonlocal returns
SPEcify by postconditions, Oot finds a matching library function Or equiv codecoin Oot tries to deduce formal postconditionss
python multiprocessing module
optional output args
datomic data model:
"datom": entity/attribute/value/transaction
(like RDF: subject/attribute/value + scope, except scope is just time)
transactions (time) are totally ordered and are first-class
can get the db as-of, or since or between, any transaction (transactions)
immutable
not good for write-heavy workloads, as everything must go thru the transactor
use simple graph mutation constructs in place of special case for 'before' and 'after' hooks, other AOP stuff <--- CRUCIAL
since this is a homeoiconic language of graphs, type system should mb be a graph constraint language? of course this is (iso?)morphic to logic..
category theory reifies paths
some issues topic maps introduced me to:
reification hypergraphs (needed to cleanly do more than binary relations, also negates the need to use inverse relations so much, e.g. a trinary relation between child, mother, father) distinction between pointing to the hypertext document that can be retrieved at a URI vs. pointing to the concept signified by an URI scope
came up in OAF convo:
justification stance (agree/disagree, mb also the edge labels in argument maps) provenance scope constrained target
further notes of mine:
scope temporal scope vector-clock like temporal scope, e.g. time as a partial order
notion of reference further empowered by constrained target (like empowering it to represent distinction b/t URI and concept signified by URI) constrained target as "add on"; should be able to swap out any part of standard (e.g. target) for "see this node for something that fulfills the semantic role of this, but uses a format not defined in this standard" (in this case, we use an alternative trick which might be even better; the target IS the the constrainedTarget node, which has a way of specifying a new way of finding a target)
constrained target is a way of INTRODUCING a new URI that allows us to talk about the constrained target
from Rob's PDF, a Semantic Tag subclass of Annotation: oac:Reference
Target is a reference or citation to the tag resource oac:Description
Target is a description or depiction of the tag resource oac:Classification Target is an instance of the tag resource
oac:Quality
Target has the tag resource as a quality oac:Membership
Target is a member of the set identified by the tag resource oac:Relationship
Target has a relationship [expressed or not] with the tag resourc
note that hypothes.is style annotations are none of these
"distinction between pointing to the hypertext document that can be retrieved at a URI vs. pointing to the concept signified by an URI"
mb use C-like syntax throughout, letting * and & travel from signifier to signified and vice versa (e.g. travel down a 'meta' edge as contrasted with just traveling down a normal edge -- or should these be the same, with the edge type differentiating?)?
e.g.
bob = 3 print bob
is like
global.'bob'.set(3) print *bob
also seems related to boxing and unboxing... perhaps we have our long-sought general "step down a level/step up a level" concept taking shape? but levels are just special types of edges, are they not? * and & allow a generic language of graph motions that can then be specialized by choosing the special edge type
oot graph motions, oot graph mutations (note how immutable should we be?)
a real-time garbage collector for java:
http://www.ibm.com/developerworks/java/library/j-rtj4/
notes on restrictions:
" Most roots are malleable to some degree during execution in terms of their object references. For this reason, changes to their reference set must be tracked, as we discussed in Write barriers. However, certain structures, such as the stack, can't afford the tracking of pushes and pops without significant penalties incurred on performance. Because of this, certain limitations and changes to scanning stacks are made for Metronome in keeping with the Yuasa-style barrier:
Atomic scanning of stacks. Individual thread stacks must be scanned atomically, or within a single quantum. The reason for this is that during execution, a thread can pop any number of references from its stack -- references that could have been stored elsewhere during execution. Pausing at mid-scan of a stack could cause stores to be lost track of or missed during two partial scans, creating a dangling pointer within the heap. Application developers should be aware that stacks are scanned atomically and should avoid using very deep stacks in their RT applications.
Fuzzy barrier. Although a stack must be scanned atomically, it would be difficult to keep determinism if all stacks were scanned during a single quantum. The GC and JVM are allowed to interleave execution while scanning Java stacks. This could result in objects being moved from one thread to another through a series of loads and stores. To avoid losing references to objects, threads that have not been scanned yet during a GC have the barrier track both the overwritten value and the value being stored. Tracking the stored object, should it be stored into an already processed object and popped off the stack, preserves reachability through the write barrier.
...
Issues to consider when using Metronome
Metronome strives to deliver short deterministic pauses for GC, but some situations arise both in application code and the underlying platform that can perturb these results, sometimes leading to pause-time outliers. Changes in GC behavior from what would be expected with a standard JDK collector can also occur.
The RTSJ states that GC doesn't process immortal memory. Because classes live in immortal memory, they are not subject to GC and therefore can't be unloaded. Applications expecting to use a large number of classes need to adjust immortal space appropriately, and applications that require class unloading need to make adjustments to their programming model within WebSphere? Real Time.
GC work in Metronome is time based, and any change to the hardware clock could cause hard-to-diagnose problems. An example is synchronizing the system time to a Network Time Protocol (NTP) server and then synchronizing the hardware clock to the system time. This would appear as a sudden jump in time to the GC and could cause a failure in maintaining the utilization target or possibly cause out-of-memory errors.
Running multiple JVMs on a single machine can introduce interference across the JVMs, skewing the utilization figures. The alarm thread, being a high-priority RT thread, preempts any other lower-priority thread, and the GC thread also runs at an RT priority. If sufficient GC and alarm threads are active at any time, a JVM without an active GC cycle might have its application threads preempted by another JVM's GC and alarm threads while time is actually taxed to the application because the GC for that VM is inactive.
i guess Haskell's association/binding/precedence rules make sense, except for custom precedence: left-associative, functions bind tight
should we allow infix or not?
stuff on how to write a programming language (for the jvm, or in general):
http://createyourproglang.com/
http://stackoverflow.com/questions/716613/how-to-make-a-net-or-jvm-language
http://stackoverflow.com/questions/3380498/create-a-jvm-programming-language
http://londongeeknights.wetpaint.com/page/Creating+a+language+on+the+JVM
http://www.java-forums.org/advanced-java/29920-creating-new-jvm-language.html
http://londongeeknights.wetpaint.com/page/Creating+a+language+on+the+JVM todo: http://skillsmatter.com/podcast/java-jee/language-on-jvm
some jvm bytecode tools: asm jamaica jasmin
on the beauty of having non-class-related functions in Python:
"
petercooper 21 hours ago
| link |
I notice no mentions of Ruby yet, and I wonder if this discussion is pretty much impossible to have in the Ruby world, given Ruby is solely an object oriented language, even if you try to use it procedurally. Not writing classes would be against so many Ruby conventions and accepted style that it's a non-topic?
Or is it that classes in Python specifically aren't that much of a win over the language's implementation of other paradigms? I sure haven't hit into any problems using classes or objects in Ruby, even when sometimes the use feels a little contrived to begin with, but.. I also have no choice :-) (maybe Rubyists have a Stockholm Syndrome with OO ;-))
reply
ryanf 21 hours ago
| link |
I think part of the reason this doesn't come up in Ruby is that Ruby doesn't have Python's powerful namespacing system.
In Python, it's reasonable to have a package with just functions in it, whereas in Ruby, writing a top-level method means polluting every object in the system. You can write modules that have singleton methods on them, but you still don't have anything as flexible as Python's "from pkg import foo, bar"—the caller needs to either write "ModuleName?.my_function" at every call site, or use "include" and end up with the module's methods as part of the consuming class's interface.
reply
judofyr 21 hours ago
| link |
Implicit self and late binding in Ruby makes it hard to implement a proper namespacing system without breaking other semantics :(
After working with Perl (which has a similar namespacing), I must it's something I really miss when I come back to Ruby.
reply "
gg_ 7 hours ago
| link |
I believe he is referring to this talk: http://tele-task.de/archive/video/flash/14029/
reply
gruseom 2 hours ago
| link |
Yes thanks - and if anyone watches it, be sure also to check out the stuff on Bob Barton that we posted to HN. I learned about a magnificent part of computing history thanks to that talk.
Edit: here you go:
http://news.ycombinator.com/item?id=2855500
http://news.ycombinator.com/item?id=2928672
http://news.ycombinator.com/item?id=2856567
http://news.ycombinator.com/item?id=2855508
The first two are teaser comments. The second two are the important pieces. Also the paper Kay praises at the start of the talk is short and very worth reading.
"
daviddaviddavid 18 hours ago
| link |
I dislike classes but I like bundling data along with methods which operate on that data. I often find that JavaScript?'s classless objects are a great solution. It's just so natural to be able to create an object with object literal syntax without first creating an ad hoc class and then instantiating it:
var o = {
name: 'David',
greet: function () {
console.log('Hi, I am ' + this.name);
}
};reply
jmaygarden 15 hours ago
| link |
Wouldn't this be better?
function greet(name) {
console.log('Hi, I am ' + name);
} var o = function() { greet('David'); };reply
njharman 16 hours ago
| link |
> bundling data along with methods which operate on that data
What can you possibly believe a class is other than exactly that?
reply
daviddaviddavid 4 hours ago
| link |
I realize that is one thing that classes offer. My point is that you can achieve exactly the same thing with objects rather than classes.
Very often when writing Python (or whatever) you'll create a class which is only ever instantiated once and the instantiation is done simply for the benefit of calling one method.
In such cases I find classes to be overkill. What I really want is the object. I don't need to factor the object's behavior out into a class.
Many of my sympathies are expressed much more thoroughly and eloquently in the many papers you can find online by Walter Smith outlining the motivations behind NewtonScript?.
reply
haldean 15 hours ago
| link |
Polymorphism and type hierarchies.
reply "
Python protocols reference: http://www.rafekettler.com/magicmethods.html
https://github.com/RafeKettler/magicmethods
---
in Python if D3_norm_to_D is a list and you mean to do
for (i, gene) in enumerate(D3_norm_to_D):
but you actually do
for (i, gene) in D3_norm_to_D:
you'll get
TypeError?: 'int' object is not iterable
it would be nice if the tuple destructuring routine would give a different error like 'tuple cannot be filled because 'int' object is not iterable'
--- from doug: a prob with c# is that the syntax for a primitive type (array) doesnt match the syntax for custom types:
> int[] intArray = new int[]{ 1, 2, 3, 4 ,5 }; > List<int> intList = new List<int>(){ 1, 2, 3, 4, 5 };
from steve: no if statements
(this fits in well with my search to make the syntax more homeoiconic; and to use the graph structure to represent control flows explicitly, too)
levels example?: map vs. switch vs. ???
cheap syntactic vectorization operator? or is that just part of the above map vs. switch levels generalization (we already have a map operator)
www.danielzingaro.com/extensible.pdf
---
leave some syntactic constructs to be customized, e.g. perhaps the programmer can load a library to say what text inside `` means, or what happens when a # is seen
---
dollar signs within double quotes for interpolation syntactic sugar for sprintf a la Python %
make sure DSLs at the level of Ruby on Rails are doable
---
in Python, i think
data[y-filter_shape[0]/2:y+filter_shape[0]/2+1,x-filter_shape[1]/2:x+filter_shape[1]/2+1]
!=
z = y-filter_shape[0]/2:y+filter_shape[0]/2+1,x-filter_shape[1]/2:x+filter_shape[1]/2+1 data = data[z]
but it should be..
array1[array2] should produce [array1[array2[0]], array1[array2[1]], ...] by default, unless syntax is used to 'quote' array2 to treat it like a single index into array1 or, actually i think it would be better if the quoted situation were the default, and syntax must be used to acheive the above result (syntactic map syntax? or something else?)
in Python you must do
[array1[idx] for idx in array2]
which is too verbose. with numpy it's just array1[array2].
syntactic or at least metasyntactic ability to support for things like "assert this array has no nans" "assert every member of this array isfinite" "assert every member of this array is positive" without typing out the list comprehension each time
cross-subroutine "break" and "continue" and the like via exceptions. generalize somehow (not sure how but it seems generalizable) (is this what 'colored' exceptions could do?)..
exceptions that traverse a control tree or dag or graph, like balloons navigating a maze, according to rules (constrained or Turing-complete? if like balloons, 'always go up' could be a constraint -- but mb this itself could be generalized), rather than simply going up (raising) and down (continuing after ignoring the exception if so directed by the catching exception handler) a linear stack of control frames
ok i can easily see how doing down in the call stack can be generalized to a tree (connection machine's starlisp e.g. parallelism, also nondeterminism a la nondeterministic finite automata). but how can going up be generalized?
the subroutine that called you has two meanings: it caused you to be invoked, and it is where control will return when you are done. both of these can be pluralized.
first, you can be invoked by multiple subroutines via that parallelism style in which a method is only invoked once all of its headers have been called (as each one is called it can block (or it could be asynch), forming a barrier).
second, you can return to multiple subroutines via continuation-passing (continuation passing style, cps), and you could have a list of them instead of a single continuation, just like in something like starlisp you could have a list of subroutines to call (to constrain, could limit this to data parallelism instead of control parallelism, e.g. you must call the same subroutine but with different return values -- at the least, there should be syntactic support for the data-parallel style of multiple calls and multiple returns, even if the more general control style is available)
in this way we can unify arguments and return values -- each subroutine has a variety of entry points (doors). the front door is entering via the headers. the other doors are entering via returning from subroutines. using continuations, as above, you can enter via any door at any time. and so calling and returning are unified.
i feel like primitives like 'any' and 'all' will be important in any constrained languagefor balloon rising (exceptions navigating through a maze).
is the intelligence of the balloon navigating the maze in the maze walls or in the balloon (in the exception or in the exception handlers?) it seems like "both" is an easy answer, but is it the right one? something tells me that it should be in the exception handlers -- if you make the 'balloon' 'fully aware' then it' just like normal program execution, so what's the point? if you put the intelligence in the walls, you can still have the balloon seem almost intelligent via coloring it and attaching 'antigens' to its 'outer coat' -- that is, it can accumulate properties (only boolean or general?) which are added and subtracted to/from it by the exception handlers as it rises.
yes, i rather like that -- there are two modes of execution, the straight-forward mode and the looking glass mode. in the former, the code at the point(s) of prior execution have control (i.e. determine the routing of the point of execution; the past controls the future), and in the latter, the 'walls', the environment the code around the potential points of future execution have control (the future controls the past).
if you can enter a subroutine via multiple doors, isn't this just GOTO? what about GOTO Considered Harmful? well, you can't just barge in via a back door, you have to be invited. first, you can only go in a back door in exception handling mode. in the inverse/looking glass/exception handling mode, it's like pattern matching in biology, the exceptions (mb not so exceptional anymore) are 'colored', or more generally display 'antigens' (boolean predicates, or more likely just generic data against which boolean predicates can match), and the handlers, the 'back doors', are like receptors, gates defined by boolean predicates which match only some exceptions. There are multiple 'spaces' of exceptions floating around to be scanned (like the 'blackboard' parallelization scheme). you could also consider the "lock and key" metaphor in which the key must be specifically granted to the bearer by a party connected to someone who owns the house (i.e. at some time in the past, you have had to get a continuation for a point of entry by passing through that subroutine, and without this continuation you cannot match the gate). maybe this is the more general case of the special case of exception handling, which might have the strict "lock/key/must have the continuation in hand" rule, as opposed to just a generic event-handling architecture. there is an 'up/down' direction in an exception handling space (the space in which the exceptions float around, advertising their antigens); if you call someone, or if they can return to you, you are above them (there can be cycles of course, e.g. recursion, but there is still a direction, and you can unfold/unroll these cycles if you consider each instance of a subroutine call to be a different node, rather than considering all calls to a given subroutine the same node --- btw this sort of 'unfold' operation should be a std lib function on graphs).
so... is every function call implicitly a call/cc and a function can have multiple front doors (the parallelism barrier style) and each door is passed its return arg as a continuation, and an exception can be generated and given any subset of these continuations (or other continuations which were passed in)? then the exception handlers can match on the exception. the exception itself implicitly contains a continuation, which allows for 'resume' behavior. normal function return and exceptional return are subsumed under this same general framework.
now, what is to prevent exceptions from just being general event handling? the up/down direction. an idea to implement this: you cannot pass a continuation upwards in the call stack, except for a continuation at the point that the exception was raised. that is, neither the exception object (or the return object, since now we're dealing with the general case of function returns) nor any general non-locally-scoped variable can contain as data any continuation (except, as just noted, that a return object implicitly contains a continuation to the place where it was raised (what about return objects doing normal function return? their continuation is null and using it would raise an error; they are colored as such)).
Python std errors, at least.
NotImplemented?
also remember to check out modula-2 module system, and Oberon's system, which is apparently like Modula-2 but perfected by throwing out a rarely used but difficult to implement feature (nested modules):
http://prog21.dadgum.com/136.html
also a good point: a good way of judging how good most compiler optimizations are (because they add complexity to the compiler in exchange for making the compiled programs better) is to see if they reduce the time for the compiler to compile itself:
" A Forgotten Principle of Compiler Design That a clean system for separately compiled modules appeared in Modula-2, a programming language designed by Niklaus Wirth in 1978, but not in the 2011 C++ standard...hmmm, no further comment needed. But the successor to Modula-2, Oberon, is even more interesting.
With Oberon, Wirth removed features from Modula-2 while making a few careful additions. It was a smaller language overall. Excepting the extreme minimalism of Forth, this is the first language I'm aware of where simplicity of the implementation was a concern. For example, nested modules were rarely used in Modula-2, but they were disproportionately complex to compile, so they were taken out of Oberon.
That simplicity carried over to optimizations performed by the compiler. Here's Michael Franz:
Optimizing compilers tend to be much larger and much slower than their straightforward counterparts. Their designers usually do not follow Oberon's maxim of making things "as simple as possible", but are inclined to completely disregard cost (in terms of compiler size, compilation speed, and maintainability) in favor of code-quality benefits that often turn out to be relatively marginal. Trying to make an optimizing compiler as simple as possible and yet as powerful as necessary requires, before all else, a measurement standard, by which both simplicity and power can be judged.
For a compiler that is written in the language it compiles, two such standards are easily found by considering first the time required for self-compilation, and then the size of the resulting object program. With the help of these benchmarks, one may pit simplicity against power, requiring that every new capability added to the compiler "pays its own way" by creating more benefit than cost on account of at least one of the measures.
The principle is "compiler optimizations should pay for themselves."
Clearly it's not perfect (the Oberon compiler doesn't make heavy use of floating point math, for example, so floating point optimizations may not speed it up or make it smaller), but I like the spirit of it. "
i'm guessing this is a good idea only until the language goes mainstream.
--
did a google search on modula-2 and haskell, i recall one of the designers of haskell saying that its module system is not as expressive in modula-2 but i can't see what it lacks. todo, ask the mailing list someday. one thing that it may lack is some sort of first-class-ness of data type definitions.
afaict it seems like the big module innovations in modula-2 are just what you find in Python (i know Python came later, but i am more familiar with it, so it is my point of reference): you can import things, imported things by default have qualified names, you can choose to "import as" things as unqualified names, choosing whatever name you wish. also, you can make export lists.
also, i used to think that haskell had no mechanism to specify which names you want to import, but now i think it does:
http://www.haskell.org/onlinereport/modules.html
wait, no, "Modular Type Classes" by Derek Dreyer Robert Harper Manuel M.T. Chakravarty says that indeed typeclass instances are in a global namespace
ok, i looked it up again and i think it's ML's module system that they were saying was awesome, not Haskell's
this blog post talks about why it thinks ML's module system didn't catch on: http://flyingfrogblog.blogspot.com/2010/04/mls-powerful-higher-order-module-system.html
(however, A History of Haskell: Being Lazy with Class says that the Haskell committee members simply weren't very familiar with ML's module system at the time)
toread:
https://www.google.com/search?q=ml+haskell+module&ie=utf-8&oe=utf-8&client=ubuntu&channel=fs
ML Modules and Haskell Type Classes: A Constructive Comparison http://lambda-the-ultimate.org/node/1558
--
'first-class-ify' assert statments found at the beginning and end of functions? e.g. treat them as pre- and post- conditions, and have an option to the compiler to verify if all of the preconditions for a function have been asserted in the calling function or via the post-conditions of its arguments? to get even fancier, have some limited inference.
---
mb:
strict by default but allows a "lazy" declaration, so the expressiveness of lazy, e.g. infinite data structures, separation of traversal strategy from function definition, are still possible without the user of these structures having to do anything different. typewise, everything is lazy, but it's like haskell but by default implicitly recursively strictified until it hits a barrier of a lazy declaration.
--- http://www.cs.nott.ac.uk/%7Egmh/appsem-slides/peytonjones.ppt
---
SAGE has an interesting idea: "hybrid type checking":
"Sage performs hybrid type checking of these specifications, proving or refuting as much as possible statically, and inserting runtime checks otherwise."
--- assume, check: "check" is oot's "assert" (we don't use the word 'assert' because in English, assert might have other uses and may be confused with 'assume'). "assume" means "for the purpose of type checking, assume that the following is true at this point"
---
could use ! for imperative stuff and ? for logic programming? otoh mb 'imperative stuff' is sufficiently semantic that it doesn't need punctuation (e.g. just use haskell's 'do'?)... but it is ordered...
---
also, 'commutative monads' (unordered haskell do)
---
distinction b/t mandatory and optional type checking? if we have a very expressive type system, e.g. with polymorphism and dependent types, then the type system is being used as a program verifiers, rather than its initial use in C just figure out how to compile the darn thing. contrast knowing whether something is a string or an int to bounds-checking for arrays.
there is a distinction here; the 'mandatory' component of the type system is needed to compile the code at all; the 'optional' component is needed to provably prevent certain classes of run-time crashes and errors. if the language uses hybrid type checking, a program concerned about speed might decide to omit all the run-time checks. however, a type error during compilation of the mandatory types would still lead to an error (e.g. if polymorphism is resolved at compile time, then 'you passed a string to this polymorphic function, but there is no polymorphic variant that can handle strings', although this decision could of course be pushed to runtime).
the optional component is really just a program verification/proof assistant, which can be expected to be very complex/expressive and which could perhaps not even be decidable, or not polynomially decidable. the mandatory component better darn well be decidable, and perhaps should be darn simple.
is it possible to have no mandatory component yet still have a program be compilable? e.g. to decide at compile-time on a per-instance basis if polymorphism can be resolved?
is it possible to have the optional component be extensible, e.g. can you make the language like Sage or like Qi or like Haskell at will by swapping this part out? Perhaps there could be different type-system modules just like there are different behavioral modules? this makes sense as ppl are always developing better intermediate logics
toread:
Typmix: A Framework For Implementing Modular, Extensible Type Systems A thesis submitted in partial satisfaction of the requirements for the degree Master of Science in Computer Science by Thomas Anthony Bergan
---
what is the "meaning" of programming language code? we could say it is the compiled code. This allows one to put statements in one's program that refer to its compiled version.
--- perhaps some of the complexity of Haskell's type system can be resolved not by simplifying the type system, but just by improving the UI to Haskell's type checker. one part of this is the error messages. one problem is that if a number of type signatures are, together, inconsistent, then type checker will complain about a seemingly arbitrary choice of one of these, whereas to a programmer, that one is not always where the problem is. Imposing ordering may help here. The most obvious ordering would be run-time; act as if you are interpreting the program and then the first time you hit an inconsistency, emit an error on that statement. this would be undecidable in general but in most cases there is a clear hierarchy to the program that can be deduced at compile time; e.g. "Main" has calls to Abc and Def, and Abc calls Xyz. Now if a type signature in Main which is passed to Abc causes a type signature in Abc which is passed to Xyz which is used to compute a local variable X within Xyz which conflicts with a type signature on another local variable Y within Xyz on a subsequent line, then the type system should complain about Y's type signature.
the type checker should also report the other induced types that led to the error, e.g. the types of the parameters in the Abc and Xyz calls which had a bearing on the induced type of X.
the key there is to remove the need for the programmer to 'debug' types by inserting a bunch of intermediate type signatures to find out where the problem lies.
Another thing the type checker errors could provide is examples. Rather than just saying "Something of TypeA? can't also be something of TypeB?" (e.g. "Something of type &[Int] can't also be of type [&Int]"), it should give an example for each type (e.g. "&[Int] (e.g. 0x0000 where *0x0000 = [0]) can't also be of type [&Int] (e.g. [0x0000] where *0x0000 = 0)". This might not help experienced users much (although i bet it will from time to time), but i bet the first thing that a newbie does when seeing some complicated type error is try to figure out an example of the type expression, so this saves them some energy (some will say 'but they have to learn to think!'; i say, well, turn this feature off if you want practise reading type expressions; not everyone does).
---
for shellish programming, readline_rstrip (convert a file with one string on each line to a list of strings, with no newlines in the strings) is quite useful... so are pipes... pipes are like function composition but you can independently redirect the different stdios.. interesting.. also shellish stuff brings up the concept of data-neutral field-delimited formats...
---
shellish stuff like ls *.sva
| xargs -n1 flip -m |
i guess haskell is pretty good with this sort of logic?
also many shell commands take multiple arguments anyways:
flip -m *.sva
---
for performance: predictability over erratic performance: e.g. Python's reference-counting over Java's garbage-collection with possible long pauses (altho a hybrid approach may get the best of both)
definitely no global intepreter lock; stackless python would be preferred to regular python, who cares if it's a little slower in serial
--- in Python you have to do init stuff like:
def __init__(self, shouldCancelAllUponShutdown=True):
self._shouldCancelAllUponShutdown = shouldCancelAllUponShutdown
this should be automatic---
in Python it's supposedly annoying for a subclass to override __init__, so to be safe you end up doing stuff like
def __init__(self, **kwds):
self.customInit(**kwds)instead, make the idiom to just extend __init__ and call super like usual
in fact, call make it syntactically easier to call super
---
Yegge goes on about how prototype-based dicts are really really useful:
(if you read this article, skip everything up to here) " Properties Pattern high-level overview
At a high level, every implementation of the Properties Pattern has the same core API. It's the core API for any collection that maps names to values:
get(name)
put(name, value)
has(name)
remove(name)There are typically also ways to iterate over the properties, optionally with a filter of some sort.
So the simplest implementation of the Properties Pattern is a Map of some sort. The objects in your system are Maps, and their elements are Properties.
The next step in expressive power is to reserve a special property name to represent the (optional) parent link. You can call it "parent", or "class", or "prototype", or "mommy", or anything you like. If present, it points to another Map.
Now that you have a parent link, you can enhance the semantics of get, put, has and remove to follow the parent pointer if the specified property isn't in the object's list. This is largely straightforward, with a few catches that we'll discuss below. But you should be able to envision how you'd do it without too much thought.
At this point you have a full-fledged Prototype Pattern implementation. All it took was a parent link!
From here the pattern can expand in many directions, and we'll cover a few of the interesting ones in the remainder of this article. "
after that point there are some interesting implementation notes:
"JavaScript? permits you to use arbitrary objects as keys, but what's really happening under the covers is that they're being cast to strings, and they lose their unique identity. This means JavaScript? Object property lists cannot be used as be a general-purpose hashtable with arbitrary unique objects for keys.".
"
Quoting
JavaScript?