Calling latest version number of my own functions from one of my other functions?

5 visualizaciones (últimos 30 días)
Hello!
I don't use git, but modify functions I write by appending a version number: e.g., "myfunc_3()" for the third version of myfunc().
When I update myfunc_#(), I then need to update any function that calls myfunc_#(). If I always use the same syntax, is there a workable, intelligent (simple?) way to do this? I would figure that I need no more than 99 versions of anything I write (God, I hope not!)
Thanks!
Doug Anderson
  2 comentarios
Voss
Voss el 7 de Feb. de 2022
When I need to make a new version of a function and I want to keep the old one I rename the old one first by appending _old or _backup to the name. This way the newest version always has the same name.
Of course this doesn't help in your situation, but maybe to avoid this situation in the future.
Stephen23
Stephen23 el 8 de Feb. de 2022
Editada: Stephen23 el 8 de Feb. de 2022
"If I always use the same syntax, is there a workable, intelligent (simple?) way to do this?"
The approach given by _ in the previous comment is much better: I guess that most experienced MATLAB users do some version of that. Another simpler approach is to just push the older versions into an "archive" subfolder which is not on the MATLAB search path. Incrementing the working function name like you are doing creates an unusual type of very high coupling between your fuctions (but in this case due to their names, not their functionality):
The 1st and 2nd points given in the "Disadvantages" section exactly describe your approach.
Note that your approach has no (easy) way to confirm that all references to a function were correctly updated, i.e. you could easily call different versions of a function and you would never know.
"I would figure that I need no more than 99 versions of anything I write"
You will.
But most likely this approach will be a lesson that is best learned the hard way.

Iniciar sesión para comentar.

Respuesta aceptada

DGM
DGM el 7 de Feb. de 2022
Editada: DGM el 7 de Feb. de 2022
I'm sure someone has a better way, but here's this. This just looks at all the .m files in a specified directory and replaces instances of myfunc_35() with myfunc_36(). The results are dumped into a bucket directory to avoid overwriting things.
Note the following:
  • This example only looks one directory level deep
  • Any files that aren't .m files won't be in the output directory.
  • The matching is case-sensitive and looks at preceding and following characters
  • This can't tell if it's a function call or a variable of the same name
  • This won't ignore quoted or commented instances of the pattern
oldfunction = 'myfunc_35';
newfunction = 'myfunc_36';
indir = 'mydirectoryofstuff'; % the directory to process
% you'll need to decide how you want to handle the output
% i'm just going to write all the modified files to a bucket directory
% note that this will only contain .m files!
outdir = [indir '_edit'];
if ~exist(outdir,'dir')
mkdir(outdir);
end
S = dir(fullfile(indir,'*.m'));
for fn = 1:numel(S)
alltext0 = fileread(fullfile(indir,S(fn).name)); % read the file
alltext0 = split(alltext0,newline); % split into a cell array
% replace all instances of 'myfunc_35' preceded by zero or more non-alpha
% characters, and followed immediately by a (
alltext0 = regexprep(alltext0,['(?<=[^a-zA-Z]*)' oldfunction '(?=\()'],newfunction);
fid = fopen(fullfile(outdir,S(fn).name),'w');
fprintf(fid,'%s\n',alltext0{:});
fclose(fid);
end
I've attached a test directory containing a handful of files to process.
  2 comentarios
DGM
DGM el 9 de Feb. de 2022
I knew well enough that I'm not the one to recommend best practices, but that having a means to do the bulk-renaming should be useful even if you decide to eventually transition to a different version-handling approach.

Iniciar sesión para comentar.

Más respuestas (2)

Steven Lord
Steven Lord el 8 de Feb. de 2022
The "workable, intelligent" solution would be to use a source control management system like Git.
If for whatever reason that's not an option, you could write a "canonical" version of that function that accepts inputs, passes them into an implementation function of your choice, receives the outputs from that implementation function, and returns those outputs to the caller of the canonical function.
x = myfun(0:90:360) % never changes
x = 1×5
0 1 0 -1 0
function out = myfun(in) % never changes
out = myfun1(in);
end % never changes
function out = myfun1(in) % never changes
out = sind(in); % never changes
end % never changes
function out = myfun2(in) % never changes
out = cosd(in); % never changes
end % never changes
If you wanted your script to compute the cosine of the input rather than the sine, you would change just the call inside myfun from myfun1 to myfun2. The code in the script itself would not need to change, and neither would myfun1 or myfun2. This is kind of like the facade pattern.
  5 comentarios
Walter Roberson
Walter Roberson el 9 de Feb. de 2022
I used to use rcs and cvs, both of which were not difficult to use. rcs did not handle binary objects though.
Douglas Anderson
Douglas Anderson el 10 de Feb. de 2022
Thank you all for your thoughts... and I do fit generally into the "have-to-write-code" subset! I am not a programmer, but I program, just as I am not a violist but play the viola. DGM's "I'm sure someone has a better way" is going to work for me. But, once again, thank you!

Iniciar sesión para comentar.


Walter Roberson
Walter Roberson el 8 de Feb. de 2022
Write a small class with a bunch of static properties, one for each function you need to put under the scheme. The class initialization should read a configuration file to determine which file to use the implementation for each function, and set the property to a handle to the corresponding function. Then the code would be written in terms of ClassName.GenericName such as Funs.myfunc and that would have the effect of pulling out the stored handle.
As an alternative implementation, instead of a class, write a function that returns a struct with one field for each generic, such as
function funs = Funs
funs = struct('myfunc', @myfunc_3, 'myinit', @myinit_4)
end
This would be invoked the same way as I showed for class implementation. If you added a layer with a persistent variable, it might even be faster than the class implementation.
Either way you would have to edit a control file as you moved between versions. You would not typically want to assume that the newest (highest number) is the one to use. When you are doing debugging it is very common to need to execute the latest stable version in order to compare the results of the experimental version to the stable version to be sure that you get consistent results.
That said, it might plausibly be reasonable in your situation to have initialization code that filled out the newest version automatically by examining the files, and then have a small section of fix-ups to allow reference to older versions.

Categorías

Más información sobre Environment and Settings en Help Center y File Exchange.

Productos


Versión

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by