Jump to content

C# Naming Conventions


Josh
 Share

Recommended Posts

According to MS, your namespace should actually be "company name"."product name". So the namespace for Leadwerks3D headers should be Leadwerks.Leadwerks3D. That's verbose, but okay if you just call using namespace once.

 

The lack of global functions in C# is problematic, because there really isn't a logical way to name things. In C++, we have commands like Print(), TFormPoint(), CreatePivot(). I'm not going to document different languages separately, you can see how commands are documented here:

http://www.leadwerks.com/newwiki/index.php?title=Entity::SetPosition

 

We can try to come up with different categories for global commands, but my problem with that is it won't be documented anywhere, and I think C# programmers will get confused trying to guess the proper prefix for each global command.

Log.Print();
Model.Create();
Transform.TFormPoint();

It makes more sense to me to put all global commands in a single class like "Global" or "L3D" or something:

L3D.Print();
L3D.CreateModel();
L3D.TFormPoint();

My question for the C# programmers here are:

-Does a single class for global functions look totally weird to you, or does it make sense? Have you seen this done before, and can you provide any examples?

-What would you call this class in which global functions are kept?

-If categories like FileSystem.ReadFile(), Window.Create(), and Log.Print() were used, would you feel comfortable remembering which prefix to use with what global function? These would not be documented on the function page.

 

Please answer only if you are a C# programmer.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Make it a singleton. The difference will be I can store a variable for L3D but it always gets the one same instance when I request it.

 

 

"Does a single class for global functions look totally weird to you, or does it make sense?"

It takes sense to me.

 

"Have you seen this done before, and can you provide any examples?"

Not where the entire library is setup like this. If you were starting from scratch you would do your same C++ design and so does everyone else, but via a DLL you don't have all that many options.

 

"What would you call this class in which global functions are kept?"

L3D looks good to me. Remembering different class names will be a pain. Typing L3D. and seeing the intellisense kick is in ideal.

Link to comment
Share on other sites

My goal is not to support C++, C#, or Lua the "right" way for each language. My goal is to support one uniform design that is a compromise of all three, and bend each to follow it. We may have an elegant solution to this that works uniformly with all supported languages:

 

Static functions:

http://www.leadwerks.com/newwiki/index.php?title=Static_Functions

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Does a single class for global functions look totally weird to you, or does it make sense? Have you seen this done before, and can you provide any examples?

The way to go is probably service-operation. The service is your class name, the operation is the function. This follows the WCF (Windows communication foundation) concept.

A simple example could be the logger service which has the LogToFile and LogToConsole functions (for examples sake :D)

namespace LeadWerks.LeadWerks3D.Services
{
class Logger
{
public static LogToFile(string message) {...}
public static LogToConsole(string message) {...}
}
}

 

I also strongly suggest that it is a best practice to put different services in different assemblies (not I do not use DLL's, .NET is compiled to MSIL and I don't want to confuse with native dynamic link libraries). So you could have a renderer assembly, a physics assembly, ...

 

It's also a good idea NOT to use abbreviations. The commodore64 times are over :).

 

What would you call this class in which global functions are kept?

See above...

 

If categories like FileSystem.ReadFile(), Window.Create(), and Log.Print() were used, would you feel comfortable remembering which prefix to use with what global function? These would not be documented on the function page.

Don't reinvent the wheel. The .NET libraries offer a lot of functionality out of the box. FileSystem.ReadFile() is just plain evil. Every C#.NET developer knows that he needs to use the .NET streams and readers. Before you implement, I suggest you google what you need to do and there's a fair chance that the .NET library already offers that functionality. That's how .NET developers (we have 300 of them here at work) develop, they just know the most common things and google specific functionality they don't know.

 

On the other hand, specific LWE functions should just be documented. This documentation can easily be generated from your code.

Link to comment
Share on other sites

Don't reinvent the wheel. The .NET libraries offer a lot of functionality out of the box. FileSystem.ReadFile() is just plain evil. Every C#.NET developer knows that he needs to use the .NET streams and readers. Before you implement, I suggest you google what you need to do and there's a fair chance that the .NET library already offers that functionality. That's how .NET developers (we have 300 of them here at work) develop, they just know the most common things and google specific functionality they don't know.

 

On the other hand, specific LWE functions should just be documented. This documentation can easily be generated from your code.

Yes and no. Remember the Leadwerks API has to work with C++, C, Lua and who knows what other language, which don't all have an easy FileReader available.

 

And the rest of your post, e.g. classifying "LogToConsole" in a "Logger" class boils down to what I asked Josh, but his concern was that there would be too many undocumented top classes (remember, Logger wouldn't be documented). So instead, I suggested that these static classes were built right into the C++/Lua version, so they'd be consistent with C#, Java and whatever other language. It seems like the best solution so far.

 

See this wiki page: http://www.leadwerks.com/newwiki/index.php?title=Static_Functions

Link to comment
Share on other sites

Go for a static class called something short, like LE or L3D, and put all LE functions in that class as static methods with DllImport. We can/will put wrapper classes over those anyways.

I think that anything else will lead to inconsistencies and unnecessary problems.

Link to comment
Share on other sites

Go for a static class called something short, like LE or L3D, and put all LE functions in that class as static methods with DllImport. We can/will put wrapper classes over those anyways.

I think that anything else will lead to inconsistencies and unnecessary problems.

If we are talking about C#, that's how LE.NET is done.

Roland Strålberg
Website: https://rstralberg.com

Link to comment
Share on other sites

Go for a static class called something short, like LE or L3D, and put all LE functions in that class as static methods with DllImport. We can/will put wrapper classes over those anyways.

I think that anything else will lead to inconsistencies and unnecessary problems.

 

C#/.NET with Leadwerks3D will be supported in an OOP way occifially. There will not be just the DllImport header, but an officially supported class OOP wrapper, like LEO or Leadwerks .NET for LE 2. This is because Leadwerks3D is made to be OOP by design, and not procedural, and the default commandset will be documented in an OOP way.

 

So this discussion is about how to officially support, in the OOP wrapper, the global methods.

Did I say I liked the static class approach?

Link to comment
Share on other sites

Yes and no. Remember the Leadwerks API has to work with C++, C, Lua and who knows what other language, which don't all have an easy FileReader available.

 

And the rest of your post, e.g. classifying "LogToConsole" in a "Logger" class boils down to what I asked Josh, but his concern was that there would be too many undocumented top classes (remember, Logger wouldn't be documented). So instead, I suggested that these static classes were built right into the C++/Lua version, so they'd be consistent with C#, Java and whatever other language. It seems like the best solution so far.

 

See this wiki page: http://www.leadwerks.com/newwiki/index.php?title=Static_Functions

 

I don't really agree here. What you're saying is to push limitations from one language into another... Where I see such design it goes wrong. People won't use the API where they aren't supposed to, duplication of code, bad designs, ...

It might be an option that the API is LeadWerks specific, and that a bridge is specified for each language. To take the FileReader example, custom for C++, C# uses the .NET library, Lua uses the lua capabilities, ...

 

Don't force your way of working in a language, push the language standards in your way of working.

 

Regarding the static classes build-in into the API, this means you need to expose a C interface and call all those functions with p/invoke. Isn't this a waste of time and a performance drainer? Not being documented makes no sense. If the methods are static and have the same name, you only need to document them once. The only difference is where they are and the implementation details.

Link to comment
Share on other sites

Off topic: Is it a coincidence that "Rimfrost Software" has the same initials as "Roland Stralberg"?

That's really a coincidence, haven't though of that until you mentioned it. Rimfrost Software is a registered two man company and as we live in the north of Sweden, it comes from the fact that most of the year we have than thin ice-crystal layer on everything, that' called 'rimfrost' in Swedish.

Think that is "rime" in English. Had no though of the initials, but its a nice coincidence.

 

Sometimes this works out like that without anyone planning it. I work at a company called Microbit. The two major owner first names are Micke and Robert and we are developing IT solutions. Without anyone planning it the name Microbit also could be read MICke RObert IT. Now that's also a really surprising coincidence as it was never though of when the name was decided.

Roland Strålberg
Website: https://rstralberg.com

Link to comment
Share on other sites

I don't really agree here. What you're saying is to push limitations from one language into another... Where I see such design it goes wrong. People won't use the API where they aren't supposed to, duplication of code, bad designs, ...

It might be an option that the API is LeadWerks specific, and that a bridge is specified for each language. To take the FileReader example, custom for C++, C# uses the .NET library, Lua uses the lua capabilities, ...

 

Don't force your way of working in a language, push the language standards in your way of working.

Yes, this is a valid point for a generalization. But not in our case. Static methods exist in C++, and Lua, so they are as valid as a global method.

 

Regarding the static classes build-in into the API, this means you need to expose a C interface and call all those functions with p/invoke. Isn't this a waste of time and a performance drainer?

In any case, the only way to expose a DllExport is through procedural calls. This will then be reconverted to OO calls by whichever language wrapper (note that Lua is an exception, with Lua++ and whatnot developed for it, I think).

 

From LE2, I can tell you this hasn't drained even 1 FPS from me, ever.

 

Not being documented makes no sense. If the methods are static and have the same name, you only need to document them once. The only difference is where they are and the implementation details.

Then you agree, with the static method, they'll be documented. Yay. Everyone happy.

Link to comment
Share on other sites

Yes, this is a valid point for a generalization. But not in our case. Static methods exist in C++, and Lua, so they are as valid as a global method.

Static methods exist in C#, so I don't get your point.

 

In any case, the only way to expose a DllExport is through procedural calls. This will then be reconverted to OO calls by whichever language wrapper (note that Lua is an exception, with Lua++ and whatnot developed for it, I think).

 

From LE2, I can tell you this hasn't drained even 1 FPS from me, ever.

Then you don't know what you are talking about. This is just one of the studies done about p/invoke performance. Even Microsoft admits it is a lazy way to cross language boundaries...

And now that you are talking about the language wrapper, this is where I would put the language specific implementations. File handling in the language defaults for example, not pushing in another language to replace it. Pushing it in is the easy solution, but I'm not convinced it is the best one...

 

Then you agree, with the static method, they'll be documented. Yay. Everyone happy.

Again, nothing to do with my remarks. Why couldn't a C# static method be documented?

Link to comment
Share on other sites

When the argument was about supporting C# the way MS says to, I don't really care about that, because anyone who has an opinion other than mine, or an opinion on a subject I have no opinion on, is by default wrong. :(

 

However, when the argument becomes about giving a consistent API for all languages, then it changes. Here I'm promising this guy the API is going to be 100% uniform across three languages:

http://www.leadwerks.com/werkspace/topic/4148-leadwerks-keywords-and-commands-the-same-as-others/page__view__findpost__p__36512

 

Static methods are a way to achieve that. Plus, C++ programmers have always complained about global functions like LoadModel(), even though I thought constructors were inappropriate for this. I'm surprised no one suggested static methods back when we first had that discussion, but maybe they did and I just missed it.

 

Lua already does something like this with its libraries, like time.GetTime() or whatever it's called, so we have two languages that definitely tend to use this approach, and one that's sort of undefined (C++).

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

C++ programmers have always complained about global functions like LoadModel(), even though I thought constructors were inappropriate for this.

 

Model* m = new Model("mymodel.mdl");

 

 

Ctors were made for this. The people who weren't comfortable with C++ complained because the above requires pointers. Pointers are part of the power of C++. Interestingly enough the above works in all 3 languages too :(

Link to comment
Share on other sites

Model is an abstract class. In Leadwerks3D, you are always creating an OpenGL3Model, OpenGLES2Model, etc. Constructors can't return a derived class from an abstract one.

 

What Model::Create() really does is call this:

GraphicsDriver* driver = GraphicsDriver::GetCurrent();
if (driver) return driver->CreateModel();

And in OpenGL4GraphicsDriver:

Model* OpenGL4GraphicsDriver::CreateModel()
{
return new OpenGL4Model;
}

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Model* m = new Model("mymodel.mdl");

 

 

Ctors were made for this. The people who weren't comfortable with C++ complained because the above requires pointers. Pointers are part of the power of C++. Interestingly enough the above works in all 3 languages too :rolleyes:

 

Agreed, and you don't even need pointers. You can use stack semantics if you want:

Model model("mymodel.mdl");

 

I even strongly suggest to use smart pointers (and not auto_ptr, but unique_ptr, shared_ptr and weak_ptr).

Link to comment
Share on other sites

Agreed, and you don't even need pointers. You can use stack semantics if you want:

 

Generally when you think about the design of a game and the engine you have to use pointers in some fashion. The engine has to be initialized before you can create models. Generally your entities will be in a class and so doing Model model("mymodel.mdl") in the class declaration isn't possible (not sure about the new C++ but I'm talking original C++ if you will)

 

But like Josh said, things can get tricky with his design of graphics driver making the model. He's sort of got a factory design with that, which is fine.

Link to comment
Share on other sites

Generally when you think about the design of a game and the engine you have to use pointers in some fashion. The engine has to be initialized before you can create models. Generally your entities will be in a class and so doing Model model("mymodel.mdl") in the class declaration isn't possible (not sure about the new C++ but I'm talking original C++ if you will)

 

C++ without pointers is not really the way to go, but enforcing pointer usage is generally not a best practice... I have nothing against pointers (although I prefer smart pointers over raw pointers), but it is possible to declare a Model (not pointer) and initialize it in your initializer list.

 

//header
private:
Model m_model;


//cpp
MyObject::MyObject()
:
m_model("mymodel.mdl")
{ }

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...