@ Syntax to extend Python

 

@ is the general symbol to mean "syntax extension", a variation on the basic syntax of a statement.  These extensions can be learned later, after you are comfortable with the basic syntax.  Often you can read and understand a program without understanding the details in the extensions.

Examples

squeeze = printoptions( s = None, t = '\n', f = sys.stderr )

print @squeeze x, y, z

print x, y, z @(separator = None, terminator = '\n')

print @f=myfile x, y, z

In a print statement, what follows the @ is either a user-defined 'printoptions' object, or the arguments used to create such an object, or one argument as a string with no spaces.  Keyword arguments can be a full name, or an abbreviation.  @objects may be placed anywhere after the keyword 'print'.

 

def f(x,y): @(dec1, dec2, ...) -- "decorators" on a function

statgen = defdecs(staticmethod, generator)

def f(x,y) @statgen:

def @generator f(x,y):

The syntax of function decorators is the same as printoptions above, except @objects may be placed anywhere after 'def', including the function body.

Typical decorators include: generator, staticmethod, classmethod, accepts(int,int), returns(float), onexit, singleton, docstring, author, revision date, publication status, ...

Decorators which affect the behavior of the function must come before the colon, and before any decorators that are merely comments.  The order of these behavioral decorators is significant.

 

@[] = MyList -- use MyList instead of a standard list

@{} = MyDict -- use MyDict instead of a standard dict

These might be useful when you want to change all lists in a program to add a .prepend method, or all dicts to use a special .merge method.

 

@x,y:x*x+y*y    -- compact function def ( no need for lambda )

 

@x @y @z        -- instance variables in a function definition

 

def @f(x,y):

    -- special generator, accepts new arguments with each call.

 

@return

    -- special return in a generator. ( Must be at least one.)  Next call will resume at this point.  Same as Python 'yield'.

 

raise @<test>, <data>  -- same as 'assert <test>, <data>'

 

import @debug <module> -- keep info needed for later reload.

 

@tab = '.   '   -- substitute a dot-space string for leading tabs

Guidelines

1)  Stay close to what users already know.  Don't dazzle them with "new concepts" like lambda functions.

2)  Extend, don’t' deprecate.  The @phrase should *add* options, avoiding new keywords and deprecation of existing syntax.

3)  Don't overuse @.  It should not be used for something totally new.  In every case it is an *extension* to a well-understood basic syntax.

Objections

1)  Ugh!!  It looks like Perl.  In a few years, there will be so many @ extensions that Python will look like line noise.

2)  Meaning of @ is too general.  Prefer explicit keywords for each situation.

3)  Don't need extensions.  Existing syntax is good enough.

4)  Impossible for anyone to separate "basic" from "extended" syntax.  @ will label some syntax as "second class".

Discussion

We could use another symbol.  The requirements are: no conflict with any other syntax in Python, easy to type, easy to read, and clearly distinct from the "basic" syntax of any statement where it might occur.  Other possibilities include $, %, and &, but these have other meanings that might be confusing.

 

Using new keywords or unique syntax to add each extension inevitably complicates the language for new and part-time users.  It also raises objections from users who don't need a particular extension and see it as a "wart".  It is better to have a clear separation between basic syntax and extensions. 

 

The difference between a wart and a sensible extension is that the wart is of such limited use that its value is less than the burden of having more syntax to learn.  By using @ in many similar situations, we make it a meaningful extension, not a wart.  Within the @ syntax we can have keywords as unique and descriptive as we like, and these "local keywords" won't conflict with or confuse the basic syntax.

 

No matter how good the initial design of a language, after a few years, there is inevitable pressure to extend the syntax.  Each of the examples above is debatable, but there are many enhancement requests like this, and some may be worthy of inclusion as an extension.  Using a standard extension syntax certainly beats adding warts like 'lambda' or 'print >>'.

 

The @ syntax allows limited extension of the language by users ( @[ ] etc. )  This would allow some of the flexibility of Ruby or Lisp while minimizing the risk of forking the language into many dialects that general users can't understand.