|
|
|
05-16-2020, 08:52 AM
|
#1
|
Human being with feelings
Join Date: Jan 2013
Posts: 1,126
|
dofile vs Main_OnCommand
Can somebody tell me if there's an advantage in using one or the other?
By that I mean. If I have functions I want to use in several other scripts Is it better to import the script in the action list and calling it in the other scripts using:
Code:
reaper.Main_OnCommand(reaper.NamedCommandLookup('_RSBlablabla'),0)
or just calling it directly using
Code:
dofile(reaper.GetResourcePath()..'/Scripts/myscript.lua')
|
|
|
05-16-2020, 09:52 AM
|
#2
|
Human being with feelings
Join Date: Jun 2015
Location: Indonesia Raya
Posts: 684
|
CMIIW Main_OnCommand would only work for scripts that had been added to Action List.
dofile could call the script even it’s not registered in the Action List.
|
|
|
05-16-2020, 11:10 AM
|
#3
|
Human being with feelings
Join Date: Jan 2013
Posts: 1,126
|
Well, I know that. I was asking what are the pros/cons of using one or the other.
|
|
|
05-16-2020, 04:20 PM
|
#4
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,621
|
dofile hijacks your script, that means, whatever the script does you use by dofile, it will be run first, before the rest of your script can be resumed.
Unlike Main_OnCommand, which will run the script as its own instance after your script/current defer-cycle is finished, as per Reaper's script-scheduling.
Benefits of dofile:
You can run a script within your current script immediately. It will "pause" your script for the time being. Works a little like that Feature-Request someone made, where calling Main_OnCommand shall pause the current script and resume it, after the Main_OnCommanded-script is finished.
Problems with it:
You don't know, what the dofiled-script does. It could overwrite all your variables, functions, whatever you need and create havoc in the process. Maybe this could be solved by using load instead but I haven't tried it.
This problem does not exist if you use Main_OnCommand, as the newly started script is run in its own Lua-instance, so everything in your own script is safe.
Aside of that, I think, dofile is a little faster than Main_OnCommand, but I never benchmarked this and it's more a gut-feeling on my side.
|
|
|
05-16-2020, 05:43 PM
|
#5
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by Meo-Ada Mespotine
Unlike Main_OnCommand, which will run the script as its own instance after your script/current defer-cycle is finished, as per Reaper's script-scheduling.
|
Main_OnCommand runs the action immediately and blocks until it's finished.
|
|
|
05-16-2020, 07:11 PM
|
#6
|
Human being with feelings
Join Date: Jan 2013
Posts: 1,126
|
Quote:
Originally Posted by cfillion
Main_OnCommand runs the action immediately and blocks until it's finished.
|
I wouldn’t want to contradict you but are you positive about that? I you run a command that opens a dialog, I don’t think the lua script waits for it. Does it?
|
|
|
05-16-2020, 07:15 PM
|
#7
|
Human being with feelings
Join Date: Jan 2013
Posts: 1,126
|
Quote:
Originally Posted by Meo-Ada Mespotine
Problems with it:
You don't know, what the dofiled-script does. It could overwrite all your variables, functions, whatever you need and create havoc in the process.
|
I realized that you can’t use local functions in your dofile script???
|
|
|
05-16-2020, 07:19 PM
|
#8
|
Human being with feelings
Join Date: Jan 2013
Posts: 1,126
|
Mespotine.
I seem to recall you talking about a way to do only parts of the dofile script instead of always loading your whole API all the time. Do you care to elaborate?
|
|
|
05-16-2020, 07:19 PM
|
#9
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by lexaproductions
I wouldn’t want to contradict you but are you positive about that? I you run a command that opens a dialog, I don’t think the lua script waits for it. Does it?
|
If the dialog is modal, yes:
Code:
-- File: Clean current project directory
reaper.Main_OnCommand(40098, 0) -- returns after the modal dialog is closed
reaper.ShowConsoleMsg("Executed after the project cleanup dialog is closed\n")
On the other hand, actions that open a modeless dialog returns once they've opened it so those aren't blocking.
Last edited by cfillion; 05-16-2020 at 07:39 PM.
|
|
|
05-17-2020, 07:13 AM
|
#10
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,621
|
Quote:
Originally Posted by cfillion
If the dialog is modal, yes:
Code:
-- File: Clean current project directory
reaper.Main_OnCommand(40098, 0) -- returns after the modal dialog is closed
reaper.ShowConsoleMsg("Executed after the project cleanup dialog is closed\n")
On the other hand, actions that open a modeless dialog returns once they've opened it so those aren't blocking.
|
You're right, I forgot about modal dialogs, as they influence scripts-behavior.
I even use this behaviour for exchanging the button-texts in reaper.MB().
To elaborate a little more on what that means:
The following script will run itself first, before loading the Main_OnCommand-one:
Code:
reaper.Main_OnCommand(6,0)
reaper.ShowConsoleMsg("I will be shown, before action 6 is run")
But in the following script, the order will be different:
Code:
reaper.Main_OnCommand(6,0)
reaper.MB("Tudelu","",0)
reaper.ShowConsoleMsg("I will be shown, after action 6 is run, as reaper.MB pauses the current script, allowing other scripts/actions to run in the background")
If you have modal-dialogs in the Main_OnCommanded-file, this may cause some unexpected behavior, if you're used to regular script-scheduling, but it should follow the same principle: the script, which shows a modal dialog, will be paused for the moment.
If you run an action(native and or script), which shows a modal-dialog, it will pause the currently running script as well.
For instance the following script:
Code:
reaper.Main_OnCommand(40171,0) -- insert and edit new marker, which shows a modal dialog
reaper.MB("I will be shown, after the modal-dialog of action 40171 is closed","",0)
Last edited by Meo-Ada Mespotine; 05-17-2020 at 07:30 PM.
|
|
|
05-17-2020, 07:44 AM
|
#11
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,621
|
Quote:
Originally Posted by lexaproductions
Mespotine.
I seem to recall you talking about a way to do only parts of the dofile script instead of always loading your whole API all the time. Do you care to elaborate?
|
It'll probably not help you at all, but yes.
My old way of doing it was, I loaded all the functions everytime someone added Ultraschall-API to their script. Which was very slow, so I was looking for an alternative to just load the needed functions, which
a) is easy to use and
b) takes care of dependencies of Ultraschall-API-functions in themselves
I thought about doing stuff like requesting the functions needed in the beginning of your script but quickly threw away this idea, as this needs too much work for scripters, leading them to make what I would do:
"Sistoocomplicated, I just load all them functions and be fine!"
So I looked into, what Lua has to offer, including the chance of overwriting functions, which is the most basic concept behind it.
So what I did is the following:
I split all my functions into modules. For instance, ultraschall_functions_Render_Module.lua holds all rendering-related functions.
In the past, I just dofiled this file right away. In my optimization-process, I added one more step inbetween: dummy functions.
I created a file, ultraschall_ModulatorLoad3000.lua, which holds all functions done offered by the Ultraschall-API, but as dummy functions.
These dummy functions are all like
"I am a function, related to moduleXYZ, so if I get called, dofile the module I'm in and recall me once more."
It looks something like this:
Code:
-- all the modules of Ultraschall-API(simplified for this example to the rendering-module)
ultraschall.Modules_List={
"ultraschall_functions_Render_Module.lua"
}
function ultraschall.LM(name)
-- this function loads the module by dofile, making all functions useable that are in the loaded module
-- this function is not needed but simplifies the dummy functions, so they have
-- fewer lines, making loading this dummy-functions-file a little bit faster
dofile(ultraschall.Api_Path.."/Modules/"..ultraschall.Modules_List[name])
end
function ultraschall.RenderProject_RenderTable(...)
-- if somebody calls RenderProject_RenderTable, load the rendering-module with all render-related functions(entry one in module-list)
-- after that, call the function again(as the real one is now available, passing over the parameters(...) and return it's returnvalues
-- every other use of the function RenderProject_RenderTable will now use the real one, not the dummy one
ultraschall.LM(1)
return ultraschall.RenderProject_RenderTable(table.unpack({...}))
end
Now, I dofile only ultraschall_ModulatorLoad3000.lua loading all dummy-versions of all functions, which is much faster, than loading the real ones themselves.
And everytime, someone uses an Ultraschall-API-function, it will load its module and therefore all functions within the loaded module are directly useable, from that point on.
The only case, where this approach is slightly slower, is, when you use functions from all Ultraschall-API-modules available, as you would load all modules + the dummy-functions-module ultraschall_ModulatorLoad3000.lua, but this should be a rare case. And if not, your script is probably so big, the slight increase of loading time will not affect your script anymore, as it probably does many things in timeconsuming way anyways.
|
|
|
05-17-2020, 07:14 PM
|
#12
|
Human being with feelings
Join Date: Jan 2013
Posts: 1,126
|
Quote:
Originally Posted by Meo-Ada Mespotine
It'll probably not help you at all, but yes.
My old way of doing it was, I loaded all the functions everytime someone added Ultraschall-API to their script. Which was very slow, so I was looking for an alternative to just load the needed functions, which
a) is easy to use and
b) takes care of dependencies of Ultraschall-API-functions in themselves
I thought about doing stuff like requesting the functions needed in the beginning of your script but quickly threw away this idea, as this needs too much work for scripters, leading them to make what I would do:
"Sistoocomplicated, I just load all them functions and be fine!"
So I looked into, what Lua has to offer, including the chance of overwriting functions, which is the most basic concept behind it.
So what I did is the following:
I split all my functions into modules. For instance, ultraschall_functions_Render_Module.lua holds all rendering-related functions.
In the past, I just dofiled this file right away. In my optimization-process, I added one more step inbetween: dummy functions.
I created a file, ultraschall_ModulatorLoad3000.lua, which holds all functions done offered by the Ultraschall-API, but as dummy functions.
These dummy functions are all like
"I am a function, related to moduleXYZ, so if I get called, dofile the module I'm in and recall me once more."
It looks something like this:
Code:
-- all the modules of Ultraschall-API(simplified for this example to the rendering-module)
ultraschall.Modules_List={
"ultraschall_functions_Render_Module.lua"
}
function ultraschall.LM(name)
-- this function loads the module by dofile, making all functions useable that are in the loaded module
-- this function is not needed but simplifies the dummy functions, so they have
-- fewer lines, making loading this dummy-functions-file a little bit faster
dofile(ultraschall.Api_Path.."/Modules/"..ultraschall.Modules_List[name])
end
function ultraschall.RenderProject_RenderTable(...)
-- if somebody calls RenderProject_RenderTable, load the rendering-module with all render-related functions(entry one in module-list)
-- after that, call the function again(as the real one is now available, passing over the parameters(...) and return it's returnvalues
-- every other use of the function RenderProject_RenderTable will now use the real one, not the dummy one
ultraschall.LM(1)
return ultraschall.RenderProject_RenderTable(table.unpack({...}))
end
Now, I dofile only ultraschall_ModulatorLoad3000.lua loading all dummy-versions of all functions, which is much faster, than loading the real ones themselves.
And everytime, someone uses an Ultraschall-API-function, it will load its module and therefore all functions within the loaded module are directly useable, from that point on.
The only case, where this approach is slightly slower, is, when you use functions from all Ultraschall-API-modules available, as you would load all modules + the dummy-functions-module ultraschall_ModulatorLoad3000.lua, but this should be a rare case. And if not, your script is probably so big, the slight increase of loading time will not affect your script anymore, as it probably does many things in timeconsuming way anyways.
|
Thanks a lot for all the insights.
|
|
|
09-30-2020, 06:00 AM
|
#13
|
Human being with feelings
Join Date: Jan 2013
Posts: 1,126
|
Quote:
Originally Posted by Meo-Ada Mespotine
Aside of that, I think, dofile is a little faster than Main_OnCommand, but I never benchmarked this and it's more a gut-feeling on my side.
|
Today I realized that dofile is considerably faster than Main_OnCommand:
I had a function that was counting several items:
running the script with dofile is instant but Main_OnCommand took half a second everytime.
Didn't investigate a lot, but now I becoming paranoid and feel like changing a lot of scripts with dofile because of this.
|
|
|
09-30-2020, 09:26 AM
|
#14
|
Human being with feelings
Join Date: May 2017
Location: Leipzig
Posts: 6,621
|
I might investigate into this to find a safe way to run a dofiled script, that doesn't risk the problems I wrote above.
But yeah, Main_OnCommand starts a new Lua instance before running the other script. This takes a little time which you avoid by dofile.
But you should know exactly what you are doing when dofiling a script. Main_OnCommand is usually safer(unless it's buggy to begin with) as usually no one writes scripts that take into account being run inside another script unless needed.
That's why using my Ultraschall-Api with dofile is safe, as it's designed to be dofiled.
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 06:33 PM.
|