matplotlib.mlab.find() not quite like Matlab"s

[Apologies if this message is a duplicate; it seems that Gmane ate my
previous attempt at replying, since I sent another message to the list
before acking Gmane's autoreply.]

Andrew Straw writes:

To me, nargout, like so much of Matlab, is a brutish hack introduced
because that language is not as capable or elegant as Python.

Arguably Matlab has the elegant Lisp-like feature lacking in Python of
multiple return values. In Lisp you can write

  (setq x (floor 3.14))

to set the value of x to 3, or

  (multiple-value-setq (x y) (floor 3.14))

to set the value of x to 3 and the value of y to 0.14. Note how it is
left up to the caller of the FLOOR function whether to capture just
the first returned value or both of them. This is paralleled by

  x = some_function(a,b,c)
  [x,y] = some_function(a,b,c)

where the caller decides how many values will be returned.

I imagine nargout could have arisen as an optimization aid: if a value
is not needed, the function can decide to not compute it. A reasonably
good Lisp compiler would probably do this optimization automatically,
but Matlab is (or was, until some recent version?) an interpreted
language with fewer opportunities for optimization.

Where Matlab goes terribly wrong (IMHO) is in that it encourages abuse
of the nargout mechanism: built-in functions like find change their
behavior depending on how many return values are expected. In effect,
the name "find" denotes two different functions, dispatched by the
value of nargouts.

Regardless of whether your sense of aesthetics is different than mine,
the kind of low-level shenanigans suggested as a work-around seems, at
the very least, brittle and prone to maintenance and portability
issues. (Would that even work on IronPython or PyPy?)

I imagine that the Psyco JIT compiler might have some problems with
the hack.

I would like to amend my suggestion upthread: instead of changing
mlab.find, add another function, say find2 unless someone thinks of a
better name, that always returns a tuple. The current version of find
could be left as it is, or, even better (this might be important for
automatic Matlab-to-Python translation), changed to return a single
index for any kind of array. This would require a mechanism for
addressing array elements by a single index, which probably doesn't
exist. For Matlab compatibility, the addressing should use the
column-major, i.e., Fortran, order.

In fact, I don't see why this wouldn't solve the problem of automatic
translation of functions that use nargout. The value of nargout is a
static feature of the function call, so the translator should easily
be able to dispatch according to the value, or add it as a keyword
argument. That is, if the user has a function like

  function [a,b]=foo(bar)
  switch nargout,
    case 1, a=bar;
    case 2, a=1; b=bar;

the translator could produce the Python function

  def foo(bar, nargout=0):
      if nargout==1:
          return bar;
      elif nargout==2:
          return (1,bar);

and translate




I wouldn't do this for find, since (in my experience) the
two-return-value form of find is the more common case, and it would
not be very nice to always type in the nargout parameter when using
matplotlib interactively.

it seems to me that early design mistakes resulted in terrible
backwards compatibility issues, as well. For example, I remember
being driven mad trying to figure out whether parentheses were
needed when calling certain functions. I guess for some they are
required and for others they aren't.

I wonder if this is the same problem that I had for a long time: I
finally realized that Matlab either does both auto-parenthesizing and
auto-quoting, or neither of them, so

  print -depsc2 fname

is equivalent to

  print('-depsc2', 'fname')

so if you want to create one of the parameters dynamically, you cannot
use the first form but will have to write something like

  print('-depsc2', sprintf('picture-%d', num))

(Then there is the confusion of {} vs () indexing, and cell strings
that are almost like real strings but sometimes need a {:} after them,
except that if you get them from a function, since the parser gets
confused if you type fun(param){:} so you need a temp variable, and
cell arrays of structs that sometimes act like structs of cell
arrays... Automatic translation of Matlab code will certainly have
some interesting challenges.)


Jouni K Sepp�nen