The python people haven't succinctly explained why python doesn't need "private", "protected", and "public". In one sentence, python doesn't need visibility modifiers becase...
With sufficiently good refactoring support, encapsulation decisions don't affect code evolution.
Especially according to the XP design principle of collective code ownership, it's easy to change callers of an interface when the interface changes. Though people reading the code will need to understand the changes, that's far more efficient than making artificial barriers to reuse. Encapsulation is powerful; forced encapsulation is onerous.
This is true for a single organization, no matter how large its code base. Once code is "published" however, all bets are off. Code obviously can't be refactored across administrative boundaries. That being the case, we should care about "published" instead of "public".
For encapsulation of published code, separate interfaces are much more useful than visibility keywords. A class with a single public method is better represented by a separate interface containing a single method. When that interface is published, it never changes. In Java for example, the old interface could be kept in a separate jar file, which clients can continue using even after extended versions become available.
More originally, we should allow extending code through an interface. Extending through an interface means that new code will never downcall to a method that isn't in the interface. This is an elegant solution to the fragile base class problem. (Someone recently showed me the cute new c# modifiers "new" and "override". They protect against accidental downcalls, but they don't protect against replacment of methods called by collaborating classes.)
Extending through an interface might also help with downcalling into unrelated methods with mixins and multiple inheritance. For example, to create an "artistic cowboy" with multiple inheritance, we'll inherit from "artist" and "cowboy". Though we want his artistic nature to be dominant, we don't want the cowboy method "drawAndShoot()" to downcall into the artist method "draw()". We can achieve this by extending artist through an interface that excludes "draw()".
Sunday, October 30, 2005
Monday, October 10, 2005
DRM and the Little Guy
Maybe published work isn't best treated like property, but publishers will certainly fight to keep it that way. Physical media have been pretty good at proxying ownership of information. If general purpose computers can't do as well, then publishers will just adopt special purpose devices instead. Besides keeping consumption cumbersome and inefficient, this'll give binding power to corporations, but not to individuals.
A general purpose DRM system can have a significant impact on society. If we're going to allow our computers to enter into contracts for us, we need some safeguards to avoid creating an information dystopia. The restrictions that we allow publishers to place on consumers should themselves be restricted. Generally, it shouldn't be possible for publishers to artbitrarily revoke access to their work. The set of digitally managed "rights" should be standard, easy to understand, and when possible, it should not require an ongoing relationship with the publisher.
This task is more difficult from the technology standpoint, and it'll detract from the generality of the full DRM dream, but it could work.
A general purpose DRM system can have a significant impact on society. If we're going to allow our computers to enter into contracts for us, we need some safeguards to avoid creating an information dystopia. The restrictions that we allow publishers to place on consumers should themselves be restricted. Generally, it shouldn't be possible for publishers to artbitrarily revoke access to their work. The set of digitally managed "rights" should be standard, easy to understand, and when possible, it should not require an ongoing relationship with the publisher.
This task is more difficult from the technology standpoint, and it'll detract from the generality of the full DRM dream, but it could work.
Friday, October 07, 2005
Templates for Environments
(The more surprising points are below.) Templates are useful for maintaining different deploy environments. Any large system needs to have a painless way to run in different environments, at least one "production" environment and one non-production environment. Examples of things that change between environments are: machine names, port numbers, database names.
Manually switching code from one environment to another is tedious and error-prone, but not all tools can make it completely automatic in all cases (for example, enabling stored procedures to run against differently named databases). Theoretically, templates are also be useful for unifying environment configuration across languages, but they're really essential for languages that don't support the necessary abstraction.
Even on platforms that have the necessary support, environment management can get gnarly. For example, java has a great configuration mechanism in the form of "properties" and the improved "preferences". If different sets of property files are used, however, it's easy for the non-production property sets to get out-of-date. The solution is to ensure that only a small fraction of properties are environment specific, and put only those in a separate file.
Templates generally break tools for live editing. For example, you can't "alter table" in a test database and easily have that change apply to your template. Or use a gui wizard to maintain templatized xml files for your application servers. We'd like to be able to "round-trip" templates, to be able to automatically generate templates from live files, as well as generate live files from templates. For this to be easy, the templates must meet two requirements:
An example of #2 is that a machine can't be named "foo" because substituting a template variable like "@FOO_MACHINE@" will also substitute "buffoon" and "foot".
Otherwise, the template generation will have to get complicated.
Manually switching code from one environment to another is tedious and error-prone, but not all tools can make it completely automatic in all cases (for example, enabling stored procedures to run against differently named databases). Theoretically, templates are also be useful for unifying environment configuration across languages, but they're really essential for languages that don't support the necessary abstraction.
Even on platforms that have the necessary support, environment management can get gnarly. For example, java has a great configuration mechanism in the form of "properties" and the improved "preferences". If different sets of property files are used, however, it's easy for the non-production property sets to get out-of-date. The solution is to ensure that only a small fraction of properties are environment specific, and put only those in a separate file.
Templates generally break tools for live editing. For example, you can't "alter table" in a test database and easily have that change apply to your template. Or use a gui wizard to maintain templatized xml files for your application servers. We'd like to be able to "round-trip" templates, to be able to automatically generate templates from live files, as well as generate live files from templates. For this to be easy, the templates must meet two requirements:
- there must be a one-to-one correspondence between template variables and the values in the environment used to generate templates.
- template values must be unique.
An example of #2 is that a machine can't be named "foo" because substituting a template variable like "@FOO_MACHINE@" will also substitute "buffoon" and "foot".
Otherwise, the template generation will have to get complicated.
Tuesday, August 09, 2005
Google Maps
Google maps should support saving and restoring locations.
It should also support taking the union of the sets of locations created by different API sites.
It should also support taking the union of the sets of locations created by different API sites.
Wednesday, August 03, 2005
Mixin Requirements
Proper mixins require two funny features:
but
without needing to be explicitly specified
Example 2:
UPDATE: Silly me, number one would be great for multiple inheritance also.
- never down-calling into unrelated mixins
- a mechanism for disambiguating constructor parameters
class artist:
def draw(self): ...
class cowboy:
def draw(self): ...
def drawAndShoot(): self.draw() ...
artisticCowboy = mixin(artist, cowboy)()
artisticCowboy.draw() should call artist.draw,but
artisticCowboy.drawAndShoot() should call cowboy.draw,without needing to be explicitly specified
Example 2:
class file:
def __init__(self, root): ...
class plant:
def __init__(self, root): ...we need some mechanism for specifying plant's and file's constructor parameters independentlyUPDATE: Silly me, number one would be great for multiple inheritance also.
Tuesday, August 02, 2005
Improving the GUI Editor 2
A standard XML format for representing GUIs would be a tremendous boon.
It would solve the biggest problems with current GUI builders: round-trip-ability and lockin.
It would enable a single builder to easily support GUIs that run with different languages and widget sets, including HTML.
The standard should specify the least common denominator, as well as extra features and their fall-backs. It shouldn't specify bindings or fancy template support, but it should specify how builders maintain information for features that they don't handle.
It would solve the biggest problems with current GUI builders: round-trip-ability and lockin.
It would enable a single builder to easily support GUIs that run with different languages and widget sets, including HTML.
The standard should specify the least common denominator, as well as extra features and their fall-backs. It shouldn't specify bindings or fancy template support, but it should specify how builders maintain information for features that they don't handle.
Monday, July 25, 2005
Mixins instead of Traits
On reflection (no pun intended), I can't see what advantage Traits have over mixins in a dynamic language like python. Specifically, python doesn't seem to be stuck with a total ordering.
import copy
def mixin(*classes):
c=copy.copy(classes[0])
if len(classes) > 1:
c.__bases__ += classes[1:]
return c()
class a:
def f(self): return "a.f"
def g(self): return "a.g"
class b:
def f(self): return "b.f"
def g(self): return "b.g"
class c:
def g(self): return a.g(self)
obj=mixin(c, b, a)
assert(obj.f() == "b.f")
assert(obj.g() == "a.g")
Friday, July 22, 2005
Improve the GUI Editor
Beware the GUI Editor only for a little while. For one thing, Sun is finally fixing wysiwyg layout with GroupLayout and assorted swing changes, and demonstrated in netbeans. For most of Beware's other complaints, all we really need is good template support, just like what we've been using with html for a while.
Just like with html, users usually won't care about the api for manipulating their presentation, but that's OK. (The favored api for html is the javascript dom.)
Just like with html, users usually won't care about the api for manipulating their presentation, but that's OK. (The favored api for html is the javascript dom.)
Monday, July 18, 2005
Python Shell
In the quest for best re-use, I'd like my "shell" programming language to be my main programming language, and to just support some syntactic sugar and extra functionality for interactive use.
Windowing systems obsolesce job control, leaving tab completion, history, and prompting as the important shell functionality. Python's readline bindings can handle the first two.
LazyPython and IPython both allow ommitting parantheses, commas, and quotes around function parameters. They use standard python's sys.excepthook, so that they only extend python syntax that would've illegal anyway.
This has two problems. First, there are cases that don't work, like calling a method without parameters. Second and more importantly, excepthook still throws an exception, and so discards context. That means you can't do:
So in order to do it right, we'll have to hack the interpreter, and while we're at it, we could even support working directly with the input. For example, you type
Incidentally, until we have interfaces or inference, tab completion can only work with already instantiated objects. (For example you can't complete
Windowing systems obsolesce job control, leaving tab completion, history, and prompting as the important shell functionality. Python's readline bindings can handle the first two.
LazyPython and IPython both allow ommitting parantheses, commas, and quotes around function parameters. They use standard python's sys.excepthook, so that they only extend python syntax that would've illegal anyway.
This has two problems. First, there are cases that don't work, like calling a method without parameters. Second and more importantly, excepthook still throws an exception, and so discards context. That means you can't do:
for i in range(n): some_convenient_method i.So in order to do it right, we'll have to hack the interpreter, and while we're at it, we could even support working directly with the input. For example, you type
some_convenient_method and then a space, and the interpreter inserts a paranthesis. You always have legal python code. IPython prints the legal python code after you hit return, which isn't as nice.Incidentally, until we have interfaces or inference, tab completion can only work with already instantiated objects. (For example you can't complete
list().a to list().append.)
Wednesday, July 13, 2005
Electronic Paper
Should be on my link blog, but wow, Fujitsu is demonstrating electronic paper!
Highlights: as easy-to-read as paper, extremely low-power, flexible, color. Product to be available between one and two years (April 2006 to March 2007).
Highlights: as easy-to-read as paper, extremely low-power, flexible, color. Product to be available between one and two years (April 2006 to March 2007).
Friday, June 24, 2005
Is It You?
Rule of thumb:
if you have a bad experience with someone, it's just him.
if you have a bad experience with everyone, it's you.
if you have a bad experience with someone, it's just him.
if you have a bad experience with everyone, it's you.
Tuesday, June 21, 2005
Oppressive Corporate Firewalls
If you're behind an obnoxious corporate firewall, that doesn't allow any internet access except through a web proxy, you can still get out to your unix account.
Putty supports SSL tunnelling via SSL out-of-the-box:
Putty supports SSL tunnelling via SSL out-of-the-box:
- on your server, add "Port 443" to your sshd_config
- in putty new session, specify 443 in the port box, and
- in its Connection/Proxy category, check HTTP and specify your proxy info
Monday, June 20, 2005
Perl Best Practices (for corporate coders)
In general, use perl for glue code and reports, not for business logic.
Perl code should be as simple as possible. That means:
Separate functionality out into multiple small scripts, the smallest meaningful rerunnable units. For example, have one script handle generating a report and another script handle distributing it.
Always "use strict".
Avoid using $_ in loops except for regular expressions.
Avoid reversed flow control operators except for error handling ("doSomething or die()").
Avoid redundant comments.
Avoid overloading on context. (e.g. sub fu { wantarray() ? X() : Y() })
Avoid special symbol variables. Use the long versions and "use English" (e.g. "$INPUT_RECORD_SEPARATOR" instead of $/). Comment appropriately.
Avoid using shell tools (e.g "awk", "grep", and even "date" and "cp"). If perl can do it, do it in perl.
Prefer "my" over "local".
Put "my" declarations in the tightest possible scope.
Have users of modules explicitly import the tokens that they want (e.g. "use SomeModule qw( SomeFunc $SomVar )").
Avoid writing huge modules with lots of independent functionality; people are afraid to change them.
Avoid writing modules altogether, unless you're absolutely sure that your code will be reused.
If you're using references, have the first character of the expression reflect the type of the expression (e.g. use "$somearrayref->[3]" instead of "@$somearrayref[3]").
If your "configuration" is sufficiently complex (or unchanging) just define at the top of your script.
Perl code should be as simple as possible. That means:
- Use as few language features as possible.
- Use as few lines as possible, as long as they're readable.
- Don't overdesign.
- Don't try to write perl that looks like java.
Separate functionality out into multiple small scripts, the smallest meaningful rerunnable units. For example, have one script handle generating a report and another script handle distributing it.
Always "use strict".
Avoid using $_ in loops except for regular expressions.
Avoid reversed flow control operators except for error handling ("doSomething or die()").
Avoid redundant comments.
Avoid overloading on context. (e.g. sub fu { wantarray() ? X() : Y() })
Avoid special symbol variables. Use the long versions and "use English" (e.g. "$INPUT_RECORD_SEPARATOR" instead of $/). Comment appropriately.
Avoid using shell tools (e.g "awk", "grep", and even "date" and "cp"). If perl can do it, do it in perl.
Prefer "my" over "local".
Put "my" declarations in the tightest possible scope.
Have users of modules explicitly import the tokens that they want (e.g. "use SomeModule qw( SomeFunc $SomVar )").
Avoid writing huge modules with lots of independent functionality; people are afraid to change them.
Avoid writing modules altogether, unless you're absolutely sure that your code will be reused.
If you're using references, have the first character of the expression reflect the type of the expression (e.g. use "$somearrayref->[3]" instead of "@$somearrayref[3]").
If your "configuration" is sufficiently complex (or unchanging) just define at the top of your script.
Wednesday, June 08, 2005
Next Generation Web
The next generation web will be all about abstractions for handling foreign code.
Of all the desirable features for a development platform, one of the most desirable is the ability to write and deploy code quickly and easily. This is how people explain the success of the web and web applications like the google suite.
The next generation web will protect users even from malicious code without requiring much greater responsibility. The new security will have to support three classes of features:
Of all the desirable features for a development platform, one of the most desirable is the ability to write and deploy code quickly and easily. This is how people explain the success of the web and web applications like the google suite.
The next generation web will protect users even from malicious code without requiring much greater responsibility. The new security will have to support three classes of features:
- manage state
- allow the code from one site to affect the user's experience of other sites (like greasemonkey for example)
- clearly determine what site is responsible for a given interaction (to combat phishing for example)
Thursday, May 26, 2005
Another Solution to the Fragile Base Class Problem
Here's a simple python implementation of the solution to the fragile base class problem described in Modular Reasoning in the Presence of Subtyping, and more accessibly in John Cowan's blog. It uses classes in place of "divisions".
and then:
class sgd(type):
def __init__(cls, name, bases, dct):
overridden_bases = [ base for attr in dct.keys() for base in cls.__mro__ if hasattr(base, attr) and not attr.startswith('__') ]
required_methods = [ (base,m) for base in overridden_bases for m in base.__dict__ if m not in cls.__dict__ and not m.startswith('__') ]
if required_methods:
raise "unimplemented methods:", required_methods
super(sgd, cls).__init__(name, bases, dct)
class sgd_class(object):
__metaclass__ = sgd
and then:
>>> class a(sgd_class):
... def f(self): pass
... def g(self): pass
...
>>> class b(a): pass
...
>>> class c(a):
... def f(self): pass
... def g(self): pass
...
>>> class d(a):
... def f(self): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "x.py", line 12, in __init__
if required_methods: raise "unimplemented methods:", required_methods
unimplemented methods:: [(<class '__main__.a'>, 'g')]
>>>
Monday, May 16, 2005
People Don't Read, and What To Do About It
Ever had someone flagrantly not read your email? Try putting the most important stuff at the top.
Not reading is a lot more prevalent than you think. Most people don't enjoy reading. Even those who do have too little time to read everything they'd like.
The solution is to write your emails in order of decreasing importance. Don't write in chronological order, or even in logical order. Employ the journalistic technique of "heads, decks, and leads" or headlines, sub-headlines, and leading paragraphs.
This is most important for messages to groups of people, and for documentation messages. In other situations, there isn't so much motivation to write more text than will be read.
(This is ironic as a blog post; those who see this post presumably do read. But this advice is for you! You don't realize how unusual you are.)
Not reading is a lot more prevalent than you think. Most people don't enjoy reading. Even those who do have too little time to read everything they'd like.
The solution is to write your emails in order of decreasing importance. Don't write in chronological order, or even in logical order. Employ the journalistic technique of "heads, decks, and leads" or headlines, sub-headlines, and leading paragraphs.
This is most important for messages to groups of people, and for documentation messages. In other situations, there isn't so much motivation to write more text than will be read.
(This is ironic as a blog post; those who see this post presumably do read. But this advice is for you! You don't realize how unusual you are.)
Friday, May 13, 2005
Exceptions Are Good For You
Languages with exceptions are good for you; they make you realize that your code can be interrupted any time.
Consider:
The only difference in modern languages is that the rest of a program may continue to run even after a function has been interrupted. This creates a new kind of obligation, but not a big one:
An effects system would at least catch the omission; it'd flag a function that makes multiple write calls to objects not mentioned in a
In languages without exceptions, you have to use a signal handler in the above example; in languages with exceptions, you can use a
(In the spirit of the recent exception buzz (Joel Spolsky's popularization of Raymond Chen's rant, and GvR's "resource allocation" work)
Consider:
#read user password without displaying on screen
os.system("stty -echo")
print "Password:",
password = raw_input()
os.system("stty echo")
printWhat happens if the user changes her mind, and kills the program? All subsequent typing in the shell will be invisible! Checking for errors won't help here.The only difference in modern languages is that the rest of a program may continue to run even after a function has been interrupted. This creates a new kind of obligation, but not a big one:
- you already have to worry about external state without exceptions (above example)
- you don't have to worry about local function state, because the exception causes it to be thrown out
- you do now have to worry about non-local state
An effects system would at least catch the omission; it'd flag a function that makes multiple write calls to objects not mentioned in a
finally cleanup block.In languages without exceptions, you have to use a signal handler in the above example; in languages with exceptions, you can use a
finally clause for the stty echo.(In the spirit of the recent exception buzz (Joel Spolsky's popularization of Raymond Chen's rant, and GvR's "resource allocation" work)
Friday, May 06, 2005
Click For Each Page: ACM Queue
Some sites have an obnoxious policy of requiring you to page through their content by clicking "next", "next" a bunch of times. Presumably they do this to better gauge interest in the content; the user cared enough to click to the end of the article. (Web browsers don't naturally support reporting back to the server how far the user scrolls in a page or how long a user has a page open (and focused).) Or they could just be incompetent.
To get around this, you can often click their button "Print This Article" or equivalent.
For some sites, you may have to visit the last section and then click "Print This Article" there. Cute, eh? This is how I read ACM Queue.
To get around this, you can often click their button "Print This Article" or equivalent.
For some sites, you may have to visit the last section and then click "Print This Article" there. Cute, eh? This is how I read ACM Queue.
Capacity For Self Deception
Someone should start a broad catalog of memes, not just pop-culture memes. Google book search shows our "capacity for self deception" going back to the 19th century.
Though it's easier to demonstrate this for criminals, it also applies to the best of us.
Subscribe to:
Posts (Atom)