Conventions and best practices for maintaining juce modules


#1

I am about to re-structure a lot of classes into juce modules, and am wondering how to do it right, especially since I’m about to share some of them to the public.

So what are your thoughts on…

Namespacing
I like how JUCE uses and respects namespaces, but when coding it doesn’t requireh the verbosity of fully qualified names or the problems from “using” directives.
When developing a juce module, should we just pick our own top-level namespace or put everything in a sub-namespace within juce::?

Personally I’d find it very convenient if I could just select a 3rd party module in the IntroJucer (with code in a different namespace), but have the option to automatically add “using namespace juce::somemodule” to the generated header files. Then you wouldn’t need to worry about namespaces until you run into a name clash. Any opinions on this, or how it could be done?

Module files
Is there a tool for creating the “amalgamated” module headers and .cpp files? I assume there is, because of the “START_AUTOINCLUDE” strings, but couldn’t find anything within the juce source tree. I’d like to stick to the same structure, but don’t want to maintain those manually.

git best practices
Currently I am putting my modules into a local clone of the juce repository, pull changes from jules’ repo and then push the merged tree to my private remote repo. Is this the best way to do it? It’s convenient for personal use to have my modules and the “official” ones in a single place, but…

How do I easilly merge other modules (like dRowAudio http://www.rawmaterialsoftware.com/viewtopic.php?f=6&t=8366&hilit=dRowAudio) into the right place within that repository, so they get picked up by the IntroJucer? I guess there is a smart git command to do so, but I have not yet figured out how to do it.

Also: When I want to publish my modules, I’d like to push only my module subdirectories into a public git repository (since no one will be interested in my whole juce clone). Anyone knows how this can be done best? Do I need a special repository/submodule setup from the beginning, or can I just work with my clone of juce for now and worry about “exporting” the subdirectories to another repository later?


#2

Re: namespaces, I’d say you should just use your own namespace, rather than putting it inside the juce namespace.

Yeah… Pretty trivial to make the introjucer do that, but not 100% sure if it’s the right thing to do. I added “using namespace juce” just to avoid n00bs having to do so themselves, but the “correct” thing to do is probably to leave it up to users to add their own "using"s to their header as they see fit.

There was a quick and dirty tool that I hacked together while I was refactoring everything, just because there were so many hundreds of files that I couldn’t do the job manually. But since I got everything more or less into the right place, I’ve just been maintaining them by hand. (And a lot of modules have to be written by hand anyway to get the order correct). So I don’t really want to complicate matters by releasing another utility for this pretty obscure purpose.


#3

Ok, one more question regarding namespaces. When I define my module’s classes in their own namespace, I have to qualify all juce classes with juce:: to build my module.

Is there a clever way to get around it? I only figured out two avoid it in two ways:

adding a “using namespace juce;” in the module header outside of my namespace - that seems wrong because it removes the possibility to “opt-out” via DONT_SET_USING_JUCE_NAMESPACE

adding it inside my namespace - that seems wrong because it allows things like mynamespace::String.


#4

Inside your module’s cpps, you can put “using” statements wherever you want as long as it works. But in your public headers, you should explicitly specify juce:: everywhere and not rely on shortcuts.


#5

And one more thing to avoid… never put a “using” clause into a header file!

The reason is that it applies, then, to the rest of the compilation unit - whether it’s your code or someone else’s. It means your exposing your “downstream” client to the possibility of collisions - and worse, if you update your code, your client can get a new collision even if their code hasn’t changed, perhaps a subtle collision that compiles and gives wrong answers.

Yes, Jules does have a “using juce” in ONE of his header files - but Juce is a framework, and this is an optional statement (one I personally turn off).

In fact, I personally turned that off very early on and have a file that everything includes with a lot of lines like:

[code]namespace rec { // Our namespace.

typedef juce::ApplicationCommandInfo ApplicationCommandInfo;
typedef juce::ApplicationCommandManager ApplicationCommandManager;
typedef juce::ApplicationCommandTarget ApplicationCommandTarget;

// etc. for few dozen Juce classes I use a lot.

} // namespace
[/code]
This is very practical for me - I can use these classes without qualifications in my own namespace, but I don’t get collisions with other packages.


#6

Ja, that’s exactly what I meant by saying you’d lose the option to “opt-out” of the “using namespace juce” thing. I was just hoing there was a way to “locally” import the namespace that I didn’t know about.

I’m still curious if anyone has a nice solution how to properly manage your custom modules inside the juce tree. Since I am no expert with git, I’m a bit afraid that if I start it the wrong way, I’m gonna lose my revision history at some point during refactoring if I start with a stupid repository layout.


#7

You can locally import the namespace in .cpp files. Some large number of my .cpp files start “using namespace juce”.

I’m a bit afraid that if I start it the wrong way, I’m gonna lose my revision history at some point during refactoring if I start with a stupid repository layout.

Don’t worry, you can use git move to move everything around… I’d just charge ahead and see what happens if I were you!


#8

back to namespaces: I changed a couple of my headers to use fully-qualified names for juce classes, and I didn’t like the result at all (and the work involved!)

If you write code that is specifically made to be built as a juce module, having to specify again and again that you are not using some other guys String class this time feels stupid.

So I am wondering if there are any practical disadvantages when using namespace composition in the header like this:

namespace myns {
    using namespace juce;

   // my class declarations
}

This shouldn’t pollute the global namespace, or am I missing something obious? And while it’s strange and not really wanted that it allows stuff like myns::String, the only scenario that I see where changes in my code might introduce problems for others, is when there is a name clash in the myns and juce namespaces (which I’d want to avoid anyhow).

I also wonder if I have to expect problems with certain compilers, so if anyone had good or bad experience using a similar approach, please let me know!


#9

I think you have to imagine what it’s like when someone who’s completely unfamiliar with your code tries to read it. Adding explicit namespaces instantly tells them which symbols come from an external library, and gives them the name of that library.


#10

To address your question, regarding 3rd party modules living in the Juce tree:

I would say, that this will probably not be the way to go, moving forward (although Jules has suspiciously avoided answering!)

Reason being, putting files in the Juce subtree that aren’t part of the official repository is cumbersome and hard to maintain. I would imagine, and this is just a guess, that the workflow for 3rd party modules would be to host them separately, as a typical stand alone repository (github anyone?) so that normal workflows are still usable.

For IntroJucer to know about these 3rd party modules would require a modification to IntroJucer to let the user specify additional locations to search for modules.

Since juce modules are still in their infancy, I would expect more changes ahead.


#11

I set out my module in a similar structure to the juce tree. In the root folder there are docs, apps, plugins etc. similar to the juce root structure (docs, extras etc.) and then a folder which actually contains the module’s contents. I then create a symlink to this module folder and put that in the main juce modules folder.

This way the only modification to the juce trunk is the presence of a symlink which git seems happy to ignore when performing pulls and I can mess around with my own module folder as I please.

Admittedly, relative to my module folder I do have dummy juce module folders with headers that just include the actual module header in the main juce folder. But this is only so at the top of my module header I can use #include “…/juce_audio_basics/juce_audio_basics.h” for example rather than a much longer and platform dependant module. I assume anyone who is using the module either does a similar hack or just puts the module in the juce modules folder.

While this is fine and working very well for me I can hear a wave of hacky abuse and perhaps it would be better to be able to specify additional module search locations in the Introjucer.


#12

I add the root of the juce directory to my list of searched include path, so in my own header I have

#include "modules/juce_core/juce_core.h"

for example. It would be nice if Juce would put an additional folder into the hierarchy, so my include would look like this:

#include "juce/modules/juce_core/juce_core.h"

This means that there would be a “juce” folder inside the “juce” folder. I have done the same for my own modules. My library is called “vf”, so I have includes that look like this:

#include "vf/modules/vf_core/vf_core.h"
#include "vf/modules/vf_concurrent/vf_concurrent.h"

and so on.


#13

Can we please have some of the info in here sticky or in the JUCE module section of the website...

Just been struggling to turn some code into modules. Especially the bits about namespaces.

Would be great to have a command line tool for generating the skeleton structure from a folder of files... might have a go at doing something like this with node.js at some point. 


#14

Good idea, thanks! We have a list of tutorials we're going to write, and we'll definitely add this to that list!


#15

Sorry to revive this thread, just wanted to check with the JUCE team if this is still the correct rule to apply.

I am currently in the process of converting a huge codebase which uses JUCE into the form of a juce module, and as a result all the JUCE classes in the header files of my code now demand the juce:: prefix.

I found online the following documentation (link):

using and using namespace have validity only in the same block in which they are stated or in the entire source code file if they are used directly in the global scope. For example, it would be possible to first use the objects of one namespace and then those of another one by splitting the code in different blocks

The bold part seems to imply that, if I have multiple header files like:

headerA.h:

namespace my_namespace {
    using namespace juce;
    void someStringFunction (String a);
}

headerB.h:

#include <headerA.h>
namespace my_namespace {
    using namespace juce;
    void someFileFunction (File a);
}

Then the using namespace juce is required in both headers, otherwise the one where it is missing will cause a build error due to the usage of a JUCE class (String or File) inside a block (the one declaring my_namespace) without full namespace qualifier.

That does not seem to be the case (at least with Xcode): if I remove the using namespace juce; from headerB.h, then it still builds just fine (probably because it sees that my_namespace is already using namespace juce from headerA.h).

This seems to contradict the documentation quoted before and seems equivalent to having all the typedefs in place like @TomSwirly mentioned. I don’t like that approach because I wish to explicitly import in each header files exactly the JUCE classes that I need.

With this behavior of the using keyword, the risk is that if I state using juce::String in one header, then all those headers which include it will also silently import the juce::String even if I don’t explicitly state that I am using it in each of them.

Is there any way to obtain my desired behavior, apart from prepending juce:: to all occurrences of JUCE classes in my headers?


#16

If you can structure your code to work correctly with using namespace juce declarations, then great - go for it!

My suggestion above is more from the perspective of good practice, because in a public header, it’s a good idea to make it obvious to people reading the code where a particular class name comes from - otherwise if someone saw a name like “String” they might wonder whether it’s your class, or a juce class, or from some other library you’re using.


#17

Ok, I’m almost done with the refactoring of my code in the form of a juce module.

It has been easier than expected apart for a single aspect that kept confusing my brain to the point of frustrating annoyance:

Consider a generic module named “juce_module”. Its folder contains a file named juce_module.cpp, which includes all the source files that compose the module.

Unfortunately, there is another file in the IDE which is also named juce_module.cpp: it is the proxy file automatically generated by Projucer in the JuceLibraryCode directory of the client project.

That confused me so much because more often than not when clicking juce_module.cpp in the IDE, I ended up opening the proxy by mistake rather than the “real” one.

Would you consider naming the proxy files in JuceLibraryCode with a prefix or suffix to make them easily distinguishable, like use_juce_module.cpp, link_juce_module.cpp or juce_module_usage.cpp?

I believe that wouldn’t break existing projects, because all the files in JuceLibraryCode are always regenerated by Projucer anyway, together with the IDE projects.


#18

In addition, prepending the same prefix to all “proxy” files would also save from making an exception for the naming of resource files (which is, append a “_r” at the end of the name before the “.r” extension) that has been recently introduced in the following commit:

To resolve the needs described in this topic:

After having seen how easily you did introduce a change in the naming conventions of those files, I am even more persuaded that my suggestion above is feasible.


#19

Could someone from the JUCE team comment on this proposal of mine?
The details and rationale behind it are explained in my two posts before this.


#20

I can’t say I ever noticed any problems with the names being the same, but sure, I have no objections to this as a FR, it seems pretty sensible.