Namespaces: An Elegant Approach for Avoiding Name Conflicts
Posted on 2018-07-02 in the RP Photonics Software News (available as e-mail newsletter!)
Permanent link: https://www.rp-photonics.com/software_news_2018_07_02.html
Abstract: The concept of namespaces is very useful for avoiding name conflicts in programming languages. It has thus been implemented in the script language supported by software from RP Photonics - e.g. RP Fiber Power. Here, it is explained with a real-life example which awkward problems can be elegantly solved with namespaces.
There are cases where name conflicts in scripts can lead to awkward problems, and the concept of namespaces can provide a powerful solution for those. Realizing this, I have implemented this concept for our software products RP Fiber Power, RP Resonator, RP Coating and RP ProPulse.
In this article, I show you with a typical example what the problem is and how that solution with namespaces works. It may thus be of interest even for people using other programming languages offering namespaces, e.g. C++; the general ideas are the same, although the syntax is a bit different. You know, such concepts are often explained in a very abstract way; a good example from real life can be very helpful.
What's the Problem?
Imagine that we generate a computer model for a fiber amplifier with two amplifier stages based on two different fibers. For example, there could be a single-mode fiber for the preamplifier and a double-clad fiber as a power amplifier.
Our software RP Fiber Power comes with a large set of fiber data files, mostly for commercially available fibers, each one defining variables like r_co (the core radius) and functions like s_abs_Yb(l) (the absorption cross sections). The problem is quite obvious: if you simply include the data files for both fibers, the first one will define e.g. the variable r_co, and the second one will override that with its own value – a typical name conflict!
In principle, there is an easy solution: make a copy of the data file for the second fiber, where you rename all variables and functions – for example, from r_co to r_co2. Obviously, however, that is not really convenient. We could in principle deliver all those data files with variable and function names containing some product code, but that would again be relatively awkward to use: who would like to have variable names like r_co_CorActive_DCF_10_128?
How to Use Namespaces
Namespaces provide an elegant solution. Essentially, you use a namespace called stage1 for the first amplifier stage and another namespace called stage2 for the second stage. Before reading a data file, you just declare the defined namespace:
calc namespace: define stage1: begin include "Yb-Liekki Yb1200-6-125.inc" end namespace: define stage2: begin include "Yb-CorActive DCF-YB-10-128.inc" end
As a result, the variables and functions defined in the first data file get “stage1.” added to their names. For example, the core radius will be stored in stage1.r_co instead of simply r_co.
In principle, the problem is already solved with that. However, a second feature is highly convenient when later using the defined quantities. For example, you can use the following code when defining the two amplifier stages:
calc begin namespace: use stage1: begin set_device(1); set_ns('stage1'); set_fiber(L_f, No_z_steps, 'Yb'); add_ring(r_co, N_Yb); pump1 := addinputchannel(P_pump_in, l_p, 'I_p', loss_p, dir_p); signal1 := addinputchannel(P_signal_in, l_s, 'I_s', loss_s, forward); finish_fiber(); end; namespace: use stage2: begin set_device(2); set_ns('stage2'); set_fiber(L_f, No_z_steps, 'Yb'); add_ring(r_co, N_Yb); pump2 := addinputchannel(P_pump_in, l_p, 'I_p', loss_p, dir_p); signal2 := addinputchannel(P_signal_in, l_s, 'I_s', loss_s, forward); finish_fiber(); end; end
Here, we have declared within an expression that we will use a certain namespace stage1 and later stage2. As a result, we do not have to put “stage1.” or “stage2.” in front of every name; that is now done automatically.
When we write “use” instead of “define” in a namespace statement, this means that the namespace applies only to those items which can already be found in that namespace. Others, which are not defined in there, remain unaffected. For example, we really get the channel index pump1 defined, not stage1.pump1.
A further detail: by calling the function set_ns(), we tell the fiber model which namespace is associated with it. This is important because the software retrieves some fiber data from certain variables and functions – for example, it normally would take the upper-state lifetime from the variable tau_Yb, and the mentioned function call changes that to stage1.tau_Yb or stage2.tau_Yb.
There are some further tricks which I do not want to completely describe here. Just to give you some examples:
- One can always enforce the use of the global namespace by putting “std.” In front of a name.
- It is possible to exempt certain items – or just all constants – from the application of a namespace. Example: “namespace: define stage1, global constants:” would exempt all global constants.
Those who already have a user license can get a free update in order to enjoy namespaces as well – just tell us.