"global" class?

289 views
Skip to first unread message

Bart Wttewaall

unread,
Apr 14, 2011, 8:29:19 AM4/14/11
to unity3d-d...@googlegroups.com
Hi,

Does anyone know of a way to create a global-like class?
I'm not talking about static classes, let me illustrate:

In actionscript you can create a "global" class like this:

-- A file called log.as --
package {
   
    public function log(...args:Array) {
        trace(args.join(" "));
    }
   
}

That's it! No classes or constructors, and not static either. In your code you can just call log("Hello", 1, 2, 3, "world"); and it will trace it out.
You'll need to import the class, but you don't need an instance or call the static method of the class.

Now in Unity3D I'm sick and tired of typing a continuous string when I'm calling Debug.Log, so I'd like to call it with any amount of parameters:

using UnityEngine;

public sealed class Utils {
   
    public static void trace(params object[] args) {
        string output = "";
        foreach (object item in args) {
            output += item.ToString() + " ";
        }
        // remove last space char
        Debug.Log(output.Remove(output.Length-1));
    }
   
}

This works, but I need to call Utils.trace("Hello", 1, 2, 3, "world");
I'd like to omit the "Utils." part. It makes programming easier for me.
Anyone? Or shouldn't I be so frikkin' lazy? ;)
Maybe using a struct or someting?

With regards, Bart

joaquín grech

unread,
Apr 14, 2011, 8:43:18 AM4/14/11
to unity3d-d...@googlegroups.com
don't be so lazy :p

I think it could be achieved using #define but I believe unity doesn't support such thing

but seriously, Utils. seems not too much to type on control c control v world

=====================================
Joaquin Grech Gomendio
International MBA, Concentration in Finance & Entrepreneurship
IE Business School, Founder IE Spain Club, www.iespainclub.com
=====================================
This email was sent from an iPhone
--
You received this message because you are subscribed to the Google
Groups "Unity3D Developers" group.
To post to this group, send email to unity3d-d...@googlegroups.com
To unsubscribe from this group, send email to
unity3d-develop...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/unity3d-developers?hl=en

John Grden

unread,
Apr 14, 2011, 8:47:02 AM4/14/11
to unity3d-d...@googlegroups.com, unity3d-d...@googlegroups.com
I'll port x-ray over to a c# version for Unity and you can feel right at home ;)

Sent from my iPad

Levi Bard

unread,
Apr 14, 2011, 8:49:45 AM4/14/11
to unity3d-d...@googlegroups.com
> This works, but I need to call Utils.trace("Hello", 1, 2, 3, "world");
> I'd like to omit the "Utils." part. It makes programming easier for me.
> Anyone? Or shouldn't I be so frikkin' lazy? ;)
> Maybe using a struct or someting?

C# doesn't support this.
You could file a feature request for params args for Debug.Log() ...

John Grden

unread,
Apr 14, 2011, 9:33:48 AM4/14/11
to unity3d-d...@googlegroups.com
Hey Bart - coming from AS3 I know what you're going through :)

What you should consider is getting to know C#  ( AS3 -> C# = http://rockonflash.wordpress.com/2010/10/20/unity3d-development-actionscriptunityscript-to-c-tips/, Singletons in C# = http://rockonflash.wordpress.com/2010/10/21/singletons-in-unity3d/ )

Its a very small learning curve in terms of syntax, but you gain so much more.

If you have any questions, please don't hesitate to ping me,

John

PS> as for the global question - no, Unity doesn't allow us to things like that, which is a good thing ;)  Yes it's convenient, but it's also problematic.  hth

--
You received this message because you are subscribed to the Google
Groups "Unity3D Developers" group.
To post to this group, send email to unity3d-d...@googlegroups.com
To unsubscribe from this group, send email to
unity3d-develop...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/unity3d-developers?hl=en



--
[  JPG  ]

Bart Wttewaall

unread,
Apr 14, 2011, 10:32:13 AM4/14/11
to unity3d-d...@googlegroups.com
Hey John,
Thanks, but I'm already converted ;)

Maybe you remember a previous post of mine where I was using JS in a project. Eventually I stumbled unto bugs when using a mixed bag of C# and JS scripts. This problem, the native events and the big pile of C# code out there convinced me to drop JS and I easily moved to C#.

Now, of course, I'm still trying to desperately hold on to some AS3 patterns and techniques, but I'm easing into letting go when they don't work out in Unity3D. This trace vs Debug.Log question is one of those things ;)

Cheers, Bart

2011/4/14 John Grden <jo...@infrared5.com>

Andy Zupko

unread,
Apr 14, 2011, 10:52:07 AM4/14/11
to unity3d-d...@googlegroups.com
Sounds like you need to make a code snippet with "Util." hehe

If you REALLY hate it that much, you could always use a constructor to do the logging:

new LogMessage("my message here");

with the class just being:

class LogMessage{ public LogMessage(params){ Debug.Log("whatever");}}

Realistically though its not that much work to just type the class name before the function :D

Bart Wttewaall

unread,
Apr 14, 2011, 11:12:28 AM4/14/11
to unity3d-d...@googlegroups.com
Nah, I don't hate it. I'm just lazy, like every other efficient programmer ;)

2011/4/14 Andy Zupko <azu...@gmail.com>

Joe Schultz

unread,
Apr 14, 2011, 2:05:26 PM4/14/11
to unity3d-d...@googlegroups.com
Bart, you call yourself lazy!? HA I say! 

The truly lazy use code snippets / macros for such things & FTW! :D

Have many for Unity:
up for adding Update method,
start for adding Start method,
tr for transform
for for for loops (yep I said it)
cam for Camera.
glob for Globals., etc.

TextMate even allows you to set variables within the macro, useful for custom setting method variables, etc. Very efficient!

Seriously though, any good code editor will help solve this problem for you and do so exactly how you want it!

cheers,

joe

John Grden

unread,
Apr 14, 2011, 2:55:58 PM4/14/11
to unity3d-d...@googlegroups.com
OH sorry Bart, my bad ;)  welcome to the Dark Side.  Andy's the evil emperor in disguise.

Cliff Owen

unread,
Apr 15, 2011, 12:30:16 AM4/15/11
to unity3d-d...@googlegroups.com

I keep waiting for someone to chime in on a couple things that I think are important to note about what is going on.

 

First is that C# does cover much of this for you, especially in the case of string manipulation. Using .ToString() is implied when you’re dealing with string operators on the left. So, the following code:

 

int number = 10;

 

Debug.Log( “The number is: “ + number );

 

Does NOT require you to use number.ToString() because the data type of the left was a string… .ToString() is implied. In the following case, you must use .ToString()

 

Debug.Log( number.ToString() + “ was the number” );

 

The other is regarding memory allocation and string concatenation.

 

Functions like Debug.Log() take a string, not a reference to a string, so this is a memory copy. When things like this happen:

 

Debug.Log( “the number I picked was “ + somenumber + “ and I wanted “ + someothernumber );

 

Then the compiler knows everything up front. You will get 2 allocations (one for the new string, one for the new copy) when you build retail (but who uses Debug.Log() in retail anyway, right?).

 

When you pass in all those arguments to a function, each must be copied. Then, you don’t have the benefit of being able to pre-allocate a single string length… every single += will result in a realloc and copy of the old string + append of the new string which ultimately results in tons of allocations and the garbage collector going nuts.

 

The GOOD news in all this is that you can see all of this in the Unity Profiler. You can see, without deep profiles, how much memory functions are using as well as the time spent.

 

I watched memory in my last project climb far beyond expectation, even when everything that should have been allocated already was… but I had a per-frame Debug.Log( A+B ) concatenation going on in an Update() call. The profiler exposed it, and removing it removed the problem.

 

It’s ok to be lazy sometimes, but C# is one of those languages that will bite the lazy programmer. You should absolutely read and re-read the section on the C# language about boxing and unboxing and solidly understanding the differences between reference types and value types.

 

Oh, one last thing:

 

Debug.Log() leaves a trace in the console with a nice stack trace. Double click on the console output and it takes you to the code that generated it. If you wrap Debug.Log(), you kill that ability. You must manually look at the stack trace to figure out who called your wrapper. That extra time alone, for me, justifies not using it.

 

That’s about my 10 cents worth.

Joaquin Grech

unread,
Apr 15, 2011, 4:37:57 AM4/15/11
to unity3d-d...@googlegroups.com
Debug.Log( number.ToString() + “ was the number” );
 
you don't need ToString() there either. You don't need ToString() ever if you are concatenating strings with a +
 
the only exception would be if you are not concatenating strings. Like
Debug.Log(number1.ToString()+number2.ToString()) since it wouldn't know if you are adding numbers or adding the string. But if you put any string in between, it inmediatelly switch to string concatenation so this would work:
Debug.Log(number1+" "+number2);
 
Also, if you are concatenating strings A LOT, you shouldn't do it that way. Use StringBuilder.Append since it will not need to reallocate stuff and it will be faster/memory efficient. If you are only occasionally adding strings, you won't even notice the difference.
 
anyway, isn't this already completely off topic from the global class question? :)

 
Joaquin Grech Gomendio

International MBA, Concentration in Finance & Entrepreneurship

IE Business School, Founder IE Spain Club, www.iespainclub.com




Hendo E

unread,
Apr 15, 2011, 4:45:37 AM4/15/11
to Unity3D Developers
I am sorry, but this is ridiculous. Having global functions has
nothing to do with efficiency. If you are too lazy to type in five
more characters, create a keyboard-shortcut in your favourite IDE. Or
just get an IDE which has proper code-completition.

You may also look at C#'s extension methods where you can do something
like this:

"I am a Debug message".log();

Those are "global" functions, because they get bound to certain value
types (in the above example, you bind a function called "log" to the
string class, thus the naming "extension method").



On Apr 14, 8:29 am, Bart Wttewaall <mailinglists.wttewa...@gmail.com>
wrote:

Bart Wttewaall

unread,
May 2, 2011, 5:20:40 AM5/2/11
to unity3d-d...@googlegroups.com
So I read all your tips and remarks, and made something with it.
Here's my Utils class (where Utils should probably be renamed to something else)

As Cliff pointed out, you can double-click the console output and jump to the line.
However, since I am accustomed to Flash where you can't double-click an output
row to jump to the corresponding line, I'm not missing that functionality much.
If I need that I would of course just use Debug.Log(). I have implemented the stack trace though.

Also, I'm not particularly afraid to munch up some memory. It's not as if those traces will remain in the code forever.

Furthermore, I've added an ignoreClass method so any traces called from that class won't be shown.
Nice for when I'm debugging multiple classes without commenting out some traces that are not relevant in another class.

For all you purists out there reading this: this is just an experiment, searching for a nice way to debug.
If anyone has a better or more flexible way, please chime in.

And yes, it's way off topic now, but the topic is not what's relevant here ;)
The true question was more along the lines of: how can I create a "global" class that I can use for my debugging experiment.

Without further ado:


using UnityEngine;
using System.Collections.Generic;
using System.Diagnostics;

public sealed class Utils {
   
    /// <summary>
    /// toggle ALL traces
    /// </summary>
    public static bool verbose = true;
   
    /// <summary>
    /// toggle stacktrace output for trace()
    /// </summary>
    public static bool showStackTrace = false;
   
    /// <summary>
    /// ignore caller if its class has been listed
    /// </summary>
    private static List<string> ignoreList = new List<string>();
   
    // ---- public static methods ----
   
    /// <summary>
    /// Add an instance's classname to the ignorelist
    /// </summary>
    /// <param name="instance">
    /// A <see cref="System.Object"/>
    /// </param>
    public static void ignoreClass(object instance) {
        string caller = new StackFrame(1).GetMethod().DeclaringType.FullName;
        if (!ignoreList.Contains(caller)) ignoreList.Add(caller);
    }
   
    /// <summary>
    /// Output multiple parameters to Debug.Log()
    /// </summary>
    /// <param name="args">
    /// A <see cref="System.Object[]"/>
    /// </param>

    public static void trace(params object[] args) {
        if (!verbose) return;
       
        // ignore caller?
        string caller = new StackFrame(1).GetMethod().DeclaringType.FullName;
        if (ignoreList.Contains(caller)) return;
       
        string output = getOutput(args);
       
        if (showStackTrace) {
            // show relevant stacktrace info
            string stack = StackTraceUtility.ExtractStackTrace();
            stack = stack.Substring(stack.IndexOf("\n")); // remove first line
            UnityEngine.Debug.Log(output+stack);
           
        } else {
            // add newline for a clean output
            UnityEngine.Debug.Log(output+"\n");
        }
    }
   
    /// <summary>
    /// Output multiple parameters to Debug.Log() with additional StackTrace information
    /// </summary>
    /// <param name="args">
    /// A <see cref="System.Object[]"/>
    /// </param>
    public static void traceStack(params object[] args) {
        if (!verbose) return;
       
        // ignore caller?
        string caller = new StackFrame(1).GetMethod().DeclaringType.FullName;
        if (ignoreList.Contains(caller)) return;
       
        string output = getOutput(args);
       
        // show relevant stacktrace info
        string stack = StackTraceUtility.ExtractStackTrace();
        stack = stack.Substring(stack.IndexOf("\n")); // remove first line
        UnityEngine.Debug.Log(output+stack);
    }
   
    public static void warn(params object[] args) {
        UnityEngine.Debug.LogWarning(getOutput(args)+"\n");
    }
   
    public static void error(params object[] args) {
        UnityEngine.Debug.LogError(getOutput(args)+"\n");
    }
   
    // ---- private static methods ----
   
    private static string getOutput(object[] args) {
        string output = "";
       
        for (int i=0; i<args.Length; i++) {
            string argument = (args[i] == null) ? "Null" : args[i].ToString();
            output += argument + (i < args.Length-1 ? " " : "");
        }
       
        return output;
    }
   
}

2011/4/15 Hendo E <tokyo...@gmail.com>
Reply all
Reply to author
Forward
0 new messages