Function handles for nonexisting functions

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Function handles for nonexisting functions

Moritz Borgmann-2
In Matlab, I can create function handles to nonexisting functions
using str2func or the @ operator. Only when I try to call the
function, an error like the following occurs:

??? Undefined function or method 'blabla' for input arguments of type 'double'.

In Octave, it seems that existance of the function is checked already
upon creation of the function handle. This means that the str2func or
@ call can fail with something like

error: error creating function handle "@blabla"

which would not happen in Matlab.

Now I'm not certain how important this difference in behavior is, how
much of a conscious design decision was behind the Octave
implementation, and how much effort it would be to change. To avoid
subtle failure when porting code, I'd have a slight preference for
making the behavior compatible. What's the general opinion on this?

-M
Reply | Threaded
Open this post in threaded view
|

Function handles for nonexisting functions

John W. Eaton-6
On  4-May-2008, Moritz Borgmann wrote:

| In Matlab, I can create function handles to nonexisting functions
| using str2func or the @ operator. Only when I try to call the
| function, an error like the following occurs:
|
| ??? Undefined function or method 'blabla' for input arguments of type 'double'.
|
| In Octave, it seems that existance of the function is checked already
| upon creation of the function handle.

Up until now, I think there was no other way to do it because the
function lookup needs to be performed in the scope where the handle is
created.  With the changes I made over the last few days to support
dbup and dbdown, I think it should now be possible to simply store the
name of the function and the scope+context information and defer the
lookup.  Then when the handle is needed, the scope+context can be
reset and the lookup can be performed.

Is this really necessary?  I guess one case that could come up would
be

  fh = @some_function;
  addpath ("/dir/where/some_function/lives");
  fh ();

Is this common?  Are there other (reasonable) cases where it makes
sense to create a handle to a function that is not visible, but will
become visible later?  How did this situation come up in the code you
have?  Or were you just testing to see what would happen?

jwe

Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

Moritz Borgmann-2
>Is this really necessary?  I guess one case that could come up would
>be
>
>   fh = @some_function;
>   addpath ("/dir/where/some_function/lives");
>   fh ();

this is indeed a sick test case, which would actually work in the other brand.

>Is this common?  Are there other (reasonable) cases where it makes
>sense to create a handle to a function that is not visible, but will
>become visible later?

I can't imagine any.

>How did this situation come up in the code you
>have?

I have the situation where I'm creating function handles that I can't
know a-priori if they exist. In Matlab, str2func() always succeeds
and I can check using functions(...) if it's valid; in Octave, I have
to wrap stuff in a try...catch for the case that the function didn't
exist.

I have no particular preference myself - I think either solution is
fine. Just wanted to know what others think. If there's no other
arguments for the Matlab solution, I'd tend to leave things as they
are, simply to avoid the effort of changing (and possibly breaking)
stuff.

-M
Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

Judd Storrs
In reply to this post by John W. Eaton-6
On Mon, May 5, 2008 at 5:50 PM, Moritz Borgmann <[hidden email]> wrote:
Is this common?  Are there other (reasonable) cases where it makes
sense to create a handle to a function that is not visible, but will
become visible later?

I can't imagine any.

For what it's worth,

It may be nice if octave didn't halt until it tried to actually evaluate an invalid handle. I'm not saying it should try and repair handles but it could keep invalid handles around as invalid.

For example, the SPM/niftilib Matlab code appears to use bogus handles as a way of marking un-implemented features. They use "@crash" entries to mark some corner cases in a dispatch table. This is easy to work around by creating a crash function that crashes ;), but I don't know how common this sort of thinking is.

In this case they used "@crash" but a matlab coder could concievably get really fancy and name the undefined functions such that the error hints at which specific feature wasn't implemented.

--judd
Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

John W. Eaton
Administrator
On 22-Apr-2009, Judd Storrs wrote:

| On Mon, May 5, 2008 at 5:50 PM, Moritz Borgmann <[hidden email]> wrote:
|
| >  Is this common?  Are there other (reasonable) cases where it makes
| >> sense to create a handle to a function that is not visible, but will
| >> become visible later?
| >>
| >
| > I can't imagine any.
| >
|
| For what it's worth,
|
| It may be nice if octave didn't halt until it tried to actually evaluate an
| invalid handle. I'm not saying it should try and repair handles but it could
| keep invalid handles around as invalid.
|
| For example, the SPM/niftilib Matlab code appears to use bogus handles as a
| way of marking un-implemented features. They use "@crash" entries to mark
| some corner cases in a dispatch table. This is easy to work around by
| creating a crash function that crashes ;), but I don't know how common this
| sort of thinking is.
|
| In this case they used "@crash" but a matlab coder could concievably get
| really fancy and name the undefined functions such that the error hints at
| which specific feature wasn't implemented.

Will you please try the following with Matlab and tell me what
happens?

Create directories d1 and d2.  Put the following fucntion in
d1/crash.m:

  function crash ()
    'd1/crash'

and put the following function in d2/crash.m:

  function crash ()
    'd2/crash'

Now start Matlab in the directory that contains d1 and d2, and run the
following commands:

  fh = @crash
  fh ()
  cd d1
  fh ()
  cd ../d2
  fh ()

  clear all
  fh = @crash ()
  cd ..
  fh ()
  cd d1
  fh ()

Now, while Matlab is still running, change the definition of
d2/crash.m to be

  function crash ()
    'foo'

and then continue your Matlab session with the following commands:

  fh ()
  cd ..
  fh ()
  cd d2
  fh ()

  clear all
  addpath (pwd)
  cd ..
  fh = @crash
  fh ()

Now, while Matlab is still running, change the definition of
d2/crash.m to be

  function crash ()
    'bar'

and then continue your Matlab session with the following commands:

  fh ()
  cd d1
  fh ()
  cd ../d2
  fh ()

jwe
Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

Judd Storrs
On Wed, Apr 22, 2009 at 8:50 PM, John W. Eaton <[hidden email]> wrote:
Will you please try the following with Matlab and tell me what
happens?

Create directories d1 and d2.  Put the following fucntion in
d1/crash.m:

 function crash ()
   'd1/crash'

and put the following function in d2/crash.m:

 function crash ()
   'd2/crash'

Now start Matlab in the directory that contains d1 and d2, and run the
following commands:

 fh = @crash
 fh ()
 cd d1
 fh ()
 cd ../d2
 fh ()

>>  fh = @crash

fh =

    @crash

>>  fh ()
??? Undefined function or variable 'crash'.

>>  cd d1
>>  fh ()

ans =

d1/crash

>>  cd ../d2
>>  fh ()

ans =

d2/crash
 
 clear all
 fh = @crash ()
 cd ..
 fh ()
 cd d1
 fh ()

>>  clear all
>>  fh = @crash ()
???  fh = @crash ()
                 |
Error: Unbalanced or unexpected parenthesis or bracket.

>>  cd ..
>>  fh ()
??? Undefined function or variable 'fh'.

>>  cd d1
>>  fh ()
??? Undefined function or variable 'fh'.

Now, while Matlab is still running, change the definition of
d2/crash.m to be

 function crash ()
   'foo'

and then continue your Matlab session with the following commands:

 fh ()
 cd ..
 fh ()
 cd d2
 fh ()

>>  fh ()
??? Undefined function or variable 'fh'.

>>  cd ..
>>  fh ()
??? Undefined function or variable 'fh'.

>>  cd d2
>>  fh ()
??? Undefined function or variable 'fh'.

 clear all
 addpath (pwd)
 cd ..
 fh = @crash
 fh ()

>> clear all
>> addpath(pwd)
>> cd ..
>> fh = @crash

fh =

    @crash

>> fh ()

ans =

foo
 
Now, while Matlab is still running, change the definition of
d2/crash.m to be

 function crash ()
   'bar'

and then continue your Matlab session with the following commands:

 fh ()
 cd d1
 fh ()
 cd ../d2
 fh ()

>> fh ()

ans =

bar

>> cd d1
>> fh ()

ans =

bar

>> cd ../d2
>> fh ()

ans =

bar


Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

John W. Eaton
Administrator
On 22-Apr-2009, Judd Storrs wrote:

| >>  clear all
| >>  fh = @crash ()
| ???  fh = @crash ()
|                  |
| Error: Unbalanced or unexpected parenthesis or bracket.

Sorry, that was a mistake.  The line should not have had the ().  Can
you change the line to "fh = @crash" and rerun the example from the
beginning and post the complete results?

jwe
Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

Judd Storrs
In reply to this post by John W. Eaton
On Wed, Apr 22, 2009 at 8:50 PM, John W. Eaton <[hidden email]> wrote:
Create directories d1 and d2.  Put the following fucntion in
d1/crash.m:

 function crash ()
   'd1/crash'

and put the following function in d2/crash.m:

 function crash ()
   'd2/crash'

Now start Matlab in the directory that contains d1 and d2, and run the
following commands:

 fh = @crash
 fh ()
 cd d1
 fh ()
 cd ../d2
 fh ()

>> fh = @crash

fh =

    @crash

>> fh ()
??? Undefined function or variable 'crash'.

>> cd d1
>> fh ()

ans =

d1/crash

>> cd ../d2
>> fh ()

ans =

d2/crash


 clear all
 fh = @crash
 cd ..
 fh ()
 cd d1
 fh ()

>> clear all
>> fh = @crash

fh =

    @crash

>> cd ..
>> fh ()

ans =

d2/crash

>> cd d1
>> fh ()

ans =

d2/crash


Now, while Matlab is still running, change the definition of
d2/crash.m to be

 function crash ()
   'foo'

and then continue your Matlab session with the following commands:

 fh ()
 cd ..
 fh ()
 cd d2
 fh ()

>> fh ()

ans =

d2/crash

>> cd ..
>> fh ()

ans =

d2/crash

>> cd d2
>> fh ()

ans =

foo
 
clear all
 addpath (pwd)
 cd ..
 fh = @crash
 fh ()

>> clear all
>> addpath(pwd)
>> cd ..
>> fh = @crash

fh =

    @crash

>> fh ()

ans =

foo


Now, while Matlab is still running, change the definition of
d2/crash.m to be

 function crash ()
   'bar'

and then continue your Matlab session with the following commands:

 fh ()
 cd d1
 fh ()
 cd ../d2
 fh ()

>> fh ()

ans =

bar

>> cd d1
>> fh ()

ans =

bar

>> cd ../d2
>> fh ()

ans =

bar


Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

John W. Eaton
Administrator
On 22-Apr-2009, Judd Storrs wrote:

| On Wed, Apr 22, 2009 at 8:50 PM, John W. Eaton <[hidden email]> wrote:
|
| > Create directories d1 and d2.  Put the following fucntion in
| > d1/crash.m:
| >
| >  function crash ()
| >    'd1/crash'
| >
| > and put the following function in d2/crash.m:
| >
| >  function crash ()
| >    'd2/crash'
| >
| > Now start Matlab in the directory that contains d1 and d2, and run the
| > following commands:
| >
| >  fh = @crash
| >  fh ()
| >  cd d1
| >  fh ()
| >  cd ../d2
| >  fh ()
|
|
| >> fh = @crash
|
| fh =
|
|     @crash
|
| >> fh ()
| ??? Undefined function or variable 'crash'.
|
| >> cd d1
| >> fh ()
|
| ans =
|
| d1/crash
|
| >> cd ../d2
| >> fh ()
|
| ans =
|
| d2/crash

So if the function handle is not defined initially, the definition
is not sticky?  It changes depending on what function is currently
visible?

|  clear all
| >  fh = @crash
| >  cd ..
| >  fh ()
| >  cd d1
| >  fh ()
|
|
| >> clear all
| >> fh = @crash
|
| fh =
|
|     @crash
|
| >> cd ..
| >> fh ()
|
| ans =
|
| d2/crash
|
| >> cd d1
| >> fh ()
|
| ans =
|
| d2/crash

In this case, there is a function available when the handle is created
and it appears to keep its original value, so that's different from
the first case, and more like what I would expect a function handle to
do.

| Now, while Matlab is still running, change the definition of
| > d2/crash.m to be
| >
| >  function crash ()
| >    'foo'
| >
| > and then continue your Matlab session with the following commands:
| >
| >  fh ()
| >  cd ..
| >  fh ()
| >  cd d2
| >  fh ()
|
|
| >> fh ()
|
| ans =
|
| d2/crash
|
| >> cd ..
| >> fh ()
|
| ans =
|
| d2/crash
|
| >> cd d2
| >> fh ()
|
| ans =
|
| foo

Hmm...  So the new value is not picked up until you cd back to the
directory where it was first defined?  Does that make sense?  Seems
odd to me.

| > clear all
| >  addpath (pwd)
| >  cd ..
| >  fh = @crash
| >  fh ()
|
|
| >> clear all
| >> addpath(pwd)
| >> cd ..
| >> fh = @crash
|
| fh =
|
|     @crash
|
| >> fh ()
|
| ans =
|
| foo

OK, the function is found through the path.

| Now, while Matlab is still running, change the definition of
| > d2/crash.m to be
| >
| >  function crash ()
| >    'bar'
| >
| > and then continue your Matlab session with the following commands:
| >
| >  fh ()
| >  cd d1
| >  fh ()
| >  cd ../d2
| >  fh ()
|
|
| >> fh ()
|
| ans =
|
| bar
|
| >> cd d1
| >> fh ()
|
| ans =
|
| bar
|
| >> cd ../d2
| >> fh ()
|
| ans =
|
| bar

So when the function is found through an absolute path element, the
new definition is found immediately?

Ugh.  Is it just me, or does this seem like a lot of twisty special
cases?

jwe
Reply | Threaded
Open this post in threaded view
|

Fwd: Function handles for nonexisting functions

Judd Storrs
In reply to this post by Judd Storrs


---------- Forwarded message ----------
From: Judd Storrs <[hidden email]>
Date: Wed, Apr 22, 2009 at 10:14 PM
Subject: Re: Function handles for nonexisting functions
To: "John W. Eaton" <[hidden email]>
Cc: Moritz Borgmann <[hidden email]>, [hidden email]


On Wed, Apr 22, 2009 at 8:50 PM, John W. Eaton <[hidden email]> wrote:
Create directories d1 and d2.  Put the following fucntion in
d1/crash.m:

 function crash ()
   'd1/crash'

and put the following function in d2/crash.m:

 function crash ()
   'd2/crash'

Now start Matlab in the directory that contains d1 and d2, and run the
following commands:

 fh = @crash
 fh ()
 cd d1
 fh ()
 cd ../d2
 fh ()

>> fh = @crash

fh =

    @crash

>> fh ()
??? Undefined function or variable 'crash'.

>> cd d1
>> fh ()

ans =

d1/crash

>> cd ../d2
>> fh ()

ans =

d2/crash


 clear all
 fh = @crash
 cd ..
 fh ()
 cd d1
 fh ()

>> clear all
>> fh = @crash

fh =

    @crash

>> cd ..
>> fh ()

ans =

d2/crash

>> cd d1
>> fh ()

ans =

d2/crash


Now, while Matlab is still running, change the definition of
d2/crash.m to be

 function crash ()
   'foo'

and then continue your Matlab session with the following commands:

 fh ()
 cd ..
 fh ()
 cd d2
 fh ()

>> fh ()

ans =

d2/crash

>> cd ..
>> fh ()

ans =

d2/crash

>> cd d2
>> fh ()

ans =

foo
 
clear all
 addpath (pwd)
 cd ..
 fh = @crash
 fh ()

>> clear all
>> addpath(pwd)
>> cd ..
>> fh = @crash

fh =

    @crash

>> fh ()

ans =

foo


Now, while Matlab is still running, change the definition of
d2/crash.m to be

 function crash ()
   'bar'

and then continue your Matlab session with the following commands:

 fh ()
 cd d1
 fh ()
 cd ../d2
 fh ()

>> fh ()

ans =

bar

>> cd d1
>> fh ()

ans =

bar

>> cd ../d2
>> fh ()

ans =

bar



Reply | Threaded
Open this post in threaded view
|

Fwd: Function handles for nonexisting functions

Judd Storrs
In reply to this post by Judd Storrs
Sorry, forwarded the wrong one.

---------- Forwarded message ----------
From: Judd Storrs <[hidden email]>
Date: Wed, Apr 22, 2009 at 10:28 PM
Subject: Re: Function handles for nonexisting functions
To: "John W. Eaton" <[hidden email]>


It behaves differently in different versions. The version I posted first was 7.5.0.338 R2007b (the newest version I have access to). In an older version R14sp1 student edition 7.0.1.24704 the behavior is different:

                                        < M A T L A B >
                            Copyright 1984-2007 The MathWorks, Inc.
                                   Version 7.5.0.338 (R2007b)
                                         August 9, 2007




On Wed, Apr 22, 2009 at 10:14 PM, Judd Storrs <[hidden email]> wrote:
On Wed, Apr 22, 2009 at 8:50 PM, John W. Eaton <[hidden email]> wrote:
Create directories d1 and d2.  Put the following fucntion in
d1/crash.m:

 function crash ()
   'd1/crash'

and put the following function in d2/crash.m:

 function crash ()
   'd2/crash'

Now start Matlab in the directory that contains d1 and d2, and run the
following commands:

 fh = @crash
 fh ()
 cd d1
 fh ()
 cd ../d2
 fh ()

EDU>> fh = @crash

fh =

    @crash

EDU>> fh ()

??? Undefined function or variable 'crash'.

EDU>> cd d1
EDU>> fh ()

??? Undefined function or variable 'crash'.

EDU>> cd ../d2
EDU>> fh ()

??? Undefined function or variable 'crash'.

 clear all
 fh = @crash
 cd ..
 fh ()
 cd d1
 fh ()

EDU>> clear all
EDU>> fh = @crash

fh =

    @crash

EDU>> fh ()

ans =

d2/crash

EDU>> cd ..
EDU>> fh ()

ans =

d2/crash

EDU>> cd d1
EDU>> fh ()

ans =

d2/crash

Now, while Matlab is still running, change the definition of
d2/crash.m to be

 function crash ()
   'foo'

and then continue your Matlab session with the following commands:

 fh ()
 cd ..
 fh ()
 cd d2
 fh ()

EDU>> fh ()

ans =

d2/crash

EDU>> cd ..
EDU>> fh ()

ans =

d2/crash

EDU>> cd d2
EDU>> fh ()

ans =

foo
 
clear all
 addpath (pwd)
 cd ..
 fh = @crash
 fh ()

EDU>> clear all
EDU>> addpath(pwd)
EDU>> cd ..
EDU>> fh = @crash

fh =

    @crash

EDU>> fh ()


ans =

foo

Now, while Matlab is still running, change the definition of
d2/crash.m to be

 function crash ()
   'bar'

and then continue your Matlab session with the following commands:

 fh ()
 cd d1
 fh ()
 cd ../d2
 fh ()

EDU>> fh ()

ans =

bar

EDU>> cd d1
EDU>> fh ()

ans =

bar

EDU>> cd ../d2
EDU>> fh ()

ans =

bar




Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

Judd Storrs
In reply to this post by Judd Storrs
It seems to that in the older version, if the handle was invalid at creation it remains invalid always. The newer version seems to have added an extra lazy evaluation in the case of invalid handles i.e. Matlab will try to find a function in the evaluation scope at the time of evaluation before failing. The new new behavior is probably useful for rapid prototyping.

--judd


On Wed, Apr 22, 2009 at 10:32 PM, John W. Eaton <[hidden email]> wrote:
On 22-Apr-2009, Judd Storrs wrote:

| It behaves differently in different versions. The version I posted first was
| 7.5.0.338 R2007b (the newest version I have access to). In an older version
| R14sp1 student edition 7.0.1.24704 the behavior is different:

Excellent.  I love the moving targets.

jwe

Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

John W. Eaton
Administrator
On 22-Apr-2009, Judd Storrs wrote:

| It seems to that in the older version, if the handle was invalid at creation
| it remains invalid always. The newer version seems to have added an extra
| lazy evaluation in the case of invalid handles i.e. Matlab will try to find
| a function in the evaluation scope at the time of evaluation before failing.
| The new new behavior is probably useful for rapid prototyping.

That part I don't have a problem with.  It's the part about how and
when the definition can change when the referenced function changes,
and the fact that the rules seem to be different depending on whether
the function is found when the function handle is created, via a
relative or absolute directory lookup.  I don't like all the apparent
special cases.

jwe
Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

Judd Storrs
On Thu, Apr 23, 2009 at 12:20 AM, John W. Eaton <[hidden email]> wrote:
That part I don't have a problem with.  It's the part about how and
when the definition can change when the referenced function changes,
and the fact that the rules seem to be different depending on whether
the function is found when the function handle is created, via a
relative or absolute directory lookup.  I don't like all the apparent
special cases.

The simple model that seems to match the behaviour in both versions is that if the handle is invalid at creation it is always invalid. The difference between the versions is the evaluation of invalid handles. I don't think that reproducing the new behaviour exactly in octave is particularly important.

There are a number of issues with Matlab's new behavior (esp. how function pointers might interact with OOP), and I'm not sure how emulating Matlab's quirks in this domain really matters for octave for this reason -- I suspect that the reason the new behavior was added to Matlab was that it lets users create GUIs with unimplemented callbacks and then run the GUI while incrementally writing the callbacks (avoiding having to restart the GUI after each new callback is written). I could be wrong but I suspect it is very unlikely that intense scoping games are used by Matlab coders.

From your tests, the strange part (to me at least) was when Matlab doesn't realize that the handle was stale if the file wasn't in the current directory or path until you changed directory into that. I think that's probably an optimization related to Matlab cacheing parsed versions of files. Here's another example:

If I create d2/crash.m as before to return 'd2/crash'

function crash ()
'd2/crash'

Then in matlab R2007b (I've shortened the whitespace in the output)

>> cd d2
>> fh = @crash            
fh = @crash
>> fh ()
ans = d2/crash
>> cd ..
Modify d2/crash.m to return 'foo' and return to matlab:
>> fh ()
ans =d2/crash

This is what we saw before. Now I'll show you that the behavior is different if you don't evaluate fh before changing directories. Ok, now reset d2/crash.m to 'd2/creash' and restart Matlab

>> cd d2
>> fh = @crash
fh = @crash
>> cd ..
Modify d2/crash.m to return 'foo' and return to matlab:
>> fh ()
ans = foo
Modify d2/crash.m to return 'bar' and return to matlab:
>> fh ()
ans = foo

So fh kept it's definition at first use. Is that because that was the first time crash was evaluated?

Reset d2/crash.m to 'd2/crash' and restart Matlab

>> cd d2
>> fh = @crash
fh = @crash
>> crash
ans = d2/crash
>> cd ..
Modify d2/crash.m to return 'foo' and return to matlab:
>> fh ()
ans =d2/crash

So it's really Matlab's memory of d2/crash that's driving the behavior and Matlab doesn't notice that d2/crash changes unless it's in the path or current directory.

--judd
Reply | Threaded
Open this post in threaded view
|

Re: Function handles for nonexisting functions

jkirby
In reply to this post by Moritz Borgmann-2
CONTENTS DELETED
The author has deleted this message.