Calling latest version number of my own functions from one of my other functions?
2 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Douglas Anderson
le 7 Fév 2022
Commenté : Douglas Anderson
le 10 Fév 2022
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 commentaires
Voss
le 7 Fév 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
le 8 Fév 2022
Modifié(e) : Stephen23
le 8 Fév 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.
Réponse acceptée
DGM
le 7 Fév 2022
Modifié(e) : DGM
le 7 Fév 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 commentaires
DGM
le 9 Fév 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.
Plus de réponses (2)
Steven Lord
le 8 Fév 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
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 commentaires
Walter Roberson
le 9 Fév 2022
I used to use rcs and cvs, both of which were not difficult to use. rcs did not handle binary objects though.
Walter Roberson
le 8 Fév 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.
0 commentaires
Voir également
Catégories
En savoir plus sur Environment and Settings dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!