Philosophy questions - main() and encapsulation

fronobulax

Developer
Staff member
Why would I want to use main() in an ash script rather than just list the lines of code to be executed? I know that declaring main with parameters will trigger a dialog with the user to get values for those parameters, but are there any other reasons or advantages to use main()? Note this is more of a why? question than it is a how? question.

Perhaps related, encapsulation. I am tweaking code from zarqon that has a function that uses a map. The map functions as both a cache and a repository so it needs to be read from a file before the function is used and written to a file. The function could be self contained by reading and writing the map from within the function, but doing so seems somewhat inefficient in terms of disk I/O. How do (or can) I organize things so that things are stand alone and so perhaps could be reused elsewhere? The best analogy might be from an object lifecycle whereby there is a place for things to be called when then object is created and another place for where it can release resources and clean up before it is destroyed.

Thanks.
 

Bale

Minion
The reasons to use main() are tidiness, organization to improve readability and ability to include the script in another script without causing trouble. For some very simple scripts none of that seem very important and I skip main(), but most of the time I like to have it to avoid getting into trouble later on.

File_to_map() and map_to_file() are very swift. (Disk I/O speed is rarely relevant.) However, if you really want to add the data directly into the file, then feel free. The only problem is that the data cannot then be used by any other scripts. I cannot tell from your example if this matters.
 

fronobulax

Developer
Staff member
The reasons to use main() are tidiness, organization to improve readability and ability to include the script in another script without causing trouble. For some very simple scripts none of that seem very important and I skip main(), but most of the time I like to have it to avoid getting into trouble later on.
I guess my scripts and the examples I have looked at are simple :) I don't really see examples of main helping with tidiness or readability. Inclusion is another matter but again, with so much that is executed outside of main, I'm still not sure why. Maybe point me at an example?

File_to_map() and map_to_file() are very swift. (Disk I/O speed is rarely relevant.) However, if you really want to add the data directly into the file, then feel free. The only problem is that the data cannot then be used by any other scripts. I cannot tell from your example if this matters.
I don't have the code to quote, but maybe this explains a bit. I call z_function for virtually every item so it gets executed a few thousand times. z_function uses a map to cache data. If the cache/map data is recent enough then z_function returns data from the map. Otherwise it performs some actions and adds a new entry to the map or updates an existing one. I had a version of z_function that always read the map when it was called and always wrote it out before it exited. The net effect was to always read and write a file with potentially several thousand lines. There is no functional reason to do this unless it is to preserve data in the case of a crash. Reading the map, externally, before the first call to z_function and writing it once after the last call would suffice.

My sense of tidiness would rather have
Code:
do (for each item)
   z_function(item)
enddo
than
Code:
file_to_map(...)
do (for each item)
   z_function(item)
enddo
map_to_file(...)
which is why I asked the question.

Several thousand reads and writes seems to me to be inefficient although I confess that I did not run any profiling to verify that disk I/O was contributing anything noticeable to the slow speed observed.

Thanks.
 

mredge73

Member
Object oriented programing (Computer Science 102.. I think) will teach you that you want to organize your code into objects or functions and use the main() mostly as an assembler.
As your code gets more and more complex this method will grant you some organization and save additional lines of code. If you look at any of my scripts you will see a structure like that, although mine may not be as tidy as others.
I am guessing that you are building code without any functions or function calls and your scripts are rather short. If that is you style then you probably do not need a main().

As for your map question, you can look at my Item List supplemental script to see what happens when you do not use map files to organize your data.
It is very difficult to read and has many duplicate lines but still works just fine. I wrote it as a supplemental script before I was confident at using maps to store data. It is defiantly a tidiness problem because I may be the only one who can make any sense out of it.
Also, if I have to make a change to one of the thousands of lines of code I have to release a new revision and ask people who are using my script to re-download it. It desperately needs a re-write.
 

Bale

Minion
mredge73 explained things quite concisely. I may not need to add this, but I will anyway in case it helps you some more.

I guess my scripts and the examples I have looked at are simple :) I don't really see examples of main helping with tidiness or readability. Inclusion is another matter but again, with so much that is executed outside of main, I'm still not sure why. Maybe point me at an example?
Sure. Here's one of my scripts that shows what I mean about tidiness and readability. It's short, but quite well organized: Rainbow Gravitation.


My sense of tidiness would rather have
Code:
do (for each item)
   z_function(item)
enddo
than
Code:
file_to_map(...)
do (for each item)
   z_function(item)
enddo
map_to_file(...)
which is why I asked the question.
Well, actually it would look more like:

Code:
item [count(item)] = new item_data(5, 6, 7);
item [count(item)] = new item_data(1, 2, 3);
item [count(item)] = new item_data(5, 3, 8);
item [count(item)] = new item_data(3, 2, 1);
item [count(item)] = new item_data(3, 2, 1);
item [count(item)] = new item_data(1, 2, 3);
item [count(item)] = new item_data(3, 2, 1);
item [count(item)] = new item_data(3, 2, 1);
do (for each item)
   z_function(item)
enddo
But I hardly care either way. Do as you like. As I said, the main advantage is in keeping the data for use in other scripts, or saving updates for use by the same script later.
 

zarqon

Well-known member
A few additional remarks.

1) For external maps used by functions which will probably be called more than once, I recommend declaring the map globally, then loading it in the function only if count(map) == 0. This will minimize memory use as well as disk I/O.

2) This may never affect you, but be aware that if you want your script to be inclusible by a relay override script, any top-level code will prevent the script from loading. For whatever reason, all code must be inside functions for relay override scripts.

EDIT: Ha, I just realized you're probably working on a display case script! :)
 
Last edited:

fronobulax

Developer
Staff member
EDIT: Ha, I just realized you're probably working on a display case script! :)
Correct. My plan, subject to encounters with Real Life, is to post it this weekend. It isn't done, and I'm not happy with it but since the real purpose is for me to understand some scripting best practices, by actual application, I figure I need to get something in front of folks.

To others - thanks for the insights. I took Comp Sci 102 when it wasn't called Comp Sci. (I wrote my first programs using Basic on a General Electric mainframe in the 1960's. And when I walked to the computer center it was uphill both ways!). Object orientation I get and data hiding and encapsulation I get but applying best practices and personal preferences to what appears to be a procedurally oriented scripting language seems to be more taxing for me than I think it should. I have always been an advocate for reuse and for only having one copy of things and I am still trying to wrap my head around what that means and looks like in ash.

I do believe the next step for me is to study some less simple scripts and I appreciate the pointers to them.

Thanks.
 
Top