Old 05-16-2020, 08:52 AM   #1
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default 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')
lexaproductions is offline   Reply With Quote
Old 05-16-2020, 09:52 AM   #2
jrengmusic
Human being with feelings
 
jrengmusic's Avatar
 
Join Date: Jun 2015
Location: Indonesia Raya
Posts: 684
Default

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.
__________________
JRENG! | M E T R I C
jrengmusic is offline   Reply With Quote
Old 05-16-2020, 11:10 AM   #3
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Well, I know that. I was asking what are the pros/cons of using one or the other.
lexaproductions is offline   Reply With Quote
Old 05-16-2020, 04:20 PM   #4
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

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.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 05-16-2020, 05:43 PM   #5
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
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.
cfillion is offline   Reply With Quote
Old 05-16-2020, 07:11 PM   #6
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by cfillion View Post
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?
lexaproductions is offline   Reply With Quote
Old 05-16-2020, 07:15 PM   #7
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
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???
lexaproductions is offline   Reply With Quote
Old 05-16-2020, 07:19 PM   #8
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

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?
lexaproductions is offline   Reply With Quote
Old 05-16-2020, 07:19 PM   #9
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

Quote:
Originally Posted by lexaproductions View Post
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.
cfillion is offline   Reply With Quote
Old 05-17-2020, 07:13 AM   #10
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Quote:
Originally Posted by cfillion View Post
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)
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...

Last edited by Meo-Ada Mespotine; 05-17-2020 at 07:30 PM.
Meo-Ada Mespotine is offline   Reply With Quote
Old 05-17-2020, 07:44 AM   #11
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

Quote:
Originally Posted by lexaproductions View Post
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.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 05-17-2020, 07:14 PM   #12
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
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.
lexaproductions is offline   Reply With Quote
Old 09-30-2020, 06:00 AM   #13
lexaproductions
Human being with feelings
 
Join Date: Jan 2013
Posts: 1,126
Default

Quote:
Originally Posted by Meo-Ada Mespotine View Post
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.
lexaproductions is offline   Reply With Quote
Old 09-30-2020, 09:26 AM   #14
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

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.
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 06:39 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.