ItsDeltin / Overwatch-Script-To-Workshop

Converts scripts to Overwatch workshops.
208 stars 24 forks source link

RFC: Modules #219

Open Protowalker opened 3 years ago

Protowalker commented 3 years ago

As the module system is being worked on, I'd like some input from the community as to what they would like to see out of it.

What is the module system?

Modules are a way of separating your code into related sections, along with containing scopes using visibility attributes. For an example, look at the below code:

module ThisIsAModule {
    module SubModule {
        //The things in here are accessible by its siblings and its children
    }
    public module PublicSubModule {
       //anything that has access to ThisIsAModule has access to the things in here
    }
    public class Example {
      //this class can be accessed with `ThisIsAModule.Example`
    }
}

What does the module system accomplish?

Currently, there's no way of exposing certain elements of your code while keeping others private. For example, if your library creates a variable or class that's only ever used internally, there's no way to prevent the end user from attempting to use it.

//weapon_library.del
globalvar define weaponCount = 0;

rule: "example rule"
{
   weaponCount = 10;
}
//end_user.del
import "weapon_library.del";

rule: ""
{
   weaponCount = 20; //In the eyes of the library developer, this is undefined behavior
}

Pain points

1. module-level rules and variables

public module Example {
    globalvar define aVariable = 0;

   rule: "this is a rule" {

   }

   void AnExampleMethod() {
        BigMessage(AllPlayers(), aVariable);
   }
}

if we require explicit imports for creating these rules and variables, then you run into this problem:

Example.AnExampleMethod(); //this uses aVariable, but aVariable was never defined

However, not requiring explicit imports can re-introduce a problem that modules are supposed to solve, which is that the end user's namespace can become crowded. Additionally, if a library is too big and we don't require explicit imports, it could overfill the variable fill.

The best alternative I can think of is that variables shouldn't be generated unless they were used.

2. Import system Currently, imports are done by file, like this: import "anotherFile.del"; The new system will do imports like this: import Math, Color, BoardGames from CommonUtils; The question is: how will CommonUtils be defined? Should it be automatic, as in CommonUtils.del just immediately becomes the CommonUtils module, or should it be defined in another way?

For example, we can define these in their own file using JSON or TOML:

#[modules]
CommonUtils = "$MODULES/CommonUtils.del"

alternatively, we could define them in-file.

module CommonUtils from "$MODULES/CommonUtils.del";
timebomb0 commented 3 years ago

Nice! I get around most of this by having a folder called utils that houses multiple files vars.ostw, helpers.ostw, etc, and then all those files from that folder are imported into utils/index.ostw. This means everything shared throughout my code only requires import utils/index.ostw. See: https://github.com/timebomb0/OverwatchCastleRPG/tree/master/utils

In most programming languages, there is usually a pretty large negative associated with keeping everything in the global scope like this, but given the nature of Overwatch Workshop code, I haven't found many cons. If you want to be able to compile your code from multiple different file locations, then you'd have unnecessary extra vars, but I haven't seen a good use case for this.

That being said, modules seem sensible enough, as long as they're optional. I strongly recommend looking into ECMAScript's recent-ish Modules system and its implementation in Node.JS: https://nodejs.org/api/esm.html#esm_introduction

Much of it is relatively straight forward, the syntax is simple enough, sensible, and pretty well known. In regards to your latter question, I'd follow along with ECMAScript and allow any file to export modules, and then allow that file to be imported, with the requirement you must specify which exported modules you want to import.