Notifications
Clear all

[Closed] MXS coding standards: fn vs function

regarding the semicolon:
When i started out investing more time in maxscript coding i did exactly that, i transfered my C#/C++ coding habits over to maxscript. Most prominently, the semicolon endings
Later on i decided that it is even more confusing, because many other things in maxscript ( like braces v. curly braces ) do not fit into that C#/C++/Actionscript style regime, and thus lead to a constant impression that something is not quite correct

By leaving out the semi-colons, it immediatly gets apparent that this is maxscript and that you have to be prepared for some ugliness …

I always use function. Using fn doesn’t really save me that much time. Actually all my functionnames start with fn_, e.g. fn_retargetAssets or fn_exportCollada. This makes sure that I know I’m calling a function when I use it somewhere else in the script.
I use an abbreviation to start all my functions like so

function fn_NAME arg_a &outputmessage =
 (
 	/*<FUNCTION>
 	Description
 		What does the method do
 	Arguments
 		<argument_type> argument_name: argument description
 		<value by reference> outputmessage: a message we're reporting to
 	Return
 		<return_type> Function returns (anything?).
 	<FUNCTION>*/
 	if outputmessage == undefined do outputmessage = "" as stringstream
 	fnBody
 )

This helps me keep a consistent structure and forces me to document my code before I start coding. This usually helps me to flesh out the idea.

I only use fn because 1.) its shorter and 2.) I have a few abbreviations that use it.
I appreciate the argument for clarity , however.

@Klaas, I have not seen that &outputmessage thing before.
Care to explain its use? why is it using the “&” for a by reference array?

I always use “function” and all of my function names starts with capital letter.
All of my variables starts with small letter.
So, the same as grabjacket, I can recognize if I am calling a function or a variable.
The reason to use “function” – is more readable to me.
And “fn” is my abbreviation to start my function.

 PEN

Always fn as it is sorter and easier to type. I always camelCase everything. All tools are always in a struct and the structs are always formated the same way with the same base functions. This way everything looks and feels the same and runs with all my tools and I always know how to get access to them.

I think I’ve gone a bit overboard with this example, but it shows how I use the by reference parameters. This is a typical scenario where I process a scene and export the processed file. Each step in the process is a single method which does some reporting to a stringstream. In the end I present this to the user in a log, save it to a file or use in only during development.
I really like to use the by reference parameters and use them more and more in my work.

(
  	function fn_setupObjects &arrObject &outputmessage =
  	(
  		/*<FUNCTION>
  		Description
  			clears the scene and creates a bunch of boxes with varying colors
  		Arguments
  			<value by reference> arrObject: pass the created set of objects into this array
  			<value by reference> outputmessage: a message we're reporting to
  		Return
  			<boolean> true
  		<FUNCTION>*/
  		delete objects
  		arrObject = for i = 1 to 100 collect box wirecolor:(random black white) pos:(random [-100,-100,-100] [100,100,100])
  		format "Created % objects in the scene
" arrObject.count to:outputmessage
  		true
  	)
  
  	function fn_prepObjects &arrObject &outputmessage threshold:200 =
  	(
  		/*<FUNCTION>
  		Description
  			Checks the wirecolor in an array of objects and gets rid of some based on a threshold value
  		Arguments
  			<value by reference> arrObject: edit this array of objects
  			<value by reference> outputmessage: a message we're reporting to
  			<integer> threshold: a hue value used to select objects with
  		Return
  			<boolean> false if there are no objects left, true otherwise
  		<FUNCTION>*/
  		
  		local proceed = false
  		format "Prepping % objects
" arrObject.count to:outputmessage
  		local originalCount = arrObject.count
  		for i = arrObject.count to 1 by -1 do
  		(
  			if arrObject[i].wirecolor.hue > threshold then
  			(
  				arrObject[i].wirecolor = green
  			)else
  			(
  				arrObject[i].boxmode = true
  				deleteItem arrObject i
  			)
  		)
  		case arrObject.count of
  		(
  			0: (format "No object qualified for saving
" to:outputmessage;proceed = false)
  			default: (format "Excluded % objects due to wirecolor saturation
" (originalCount - arrObject.count) to:outputmessage;proceed = true)
  		)
  		proceed
  	)
  
  	function fn_prepOutputLocation strPath &outputFolder &outputmessage =
  	(
  		/*<FUNCTION>
  		Description
  			Creates a uniquely named folder to store a file in
  		Arguments
  			<string> strPath: the basepath to create a folder in
  			<value by reference> outputFolder: pass the created folderpath in here
  			<value by reference> outputmessage: a message we're reporting to
  		Return
  			<boolean> true if the folder has been created, false if not
  		<FUNCTION>*/
  		
  		local proceed = false
  		outputFolder = strPath + @"\klaasTest\" + ((genClassID returnValue:true)[1] as string) + @"\"
  		proceed = makeDir outputFolder
  		if proceed then 
  		(
  			format "Created output folder: %
" outputFolder to:outputmessage
  		)else
  		(
  			format "Couldn't create outputfolder
" to:outputmessage
  		)
  		proceed
  	)
  
  	function fn_saveObjects arrObject outputFolder &outputmessage =
  	(
  		/*<FUNCTION>
  		Description
  			Saves a bunch of objects to a max-file
  		Arguments
  			<array> arrObject: the array of objects we're saving
  			<string> outputFolder: the folder we're saving the file in
  			<value by reference> outputmessage: a message we're reporting to
  		Return
  			<boolean> true if the file has been saved, false if not
  		<FUNCTION>*/
  		
  		local proceed = false
  		local strFilePath = outputFolder + "export.max"
  		try
  		(
  			saveNodes arrObject strFilePath
  			proceed = true
  		)catch()
  		if proceed then 
  		(
  			format "Saving % objects to %
" arrObject.count strFilePath to:outputmessage
  		)else
  		(
  			format "Saving the nodes failed
" to:outputmessage
  		)
  		proceed
  	)
  
  	function event_demo threshold:200 =
  	(
  		/*<FUNCTION>
  		Description
  			Creates a set of objects, filters them and saves a few
  		Arguments
  			<integer> threshold: a value used as a filter
  		Return
  		<FUNCTION>*/
  		
  		local strMessage = "" as stringstream --all messages from the individual methods are put in this one
  		local proceed = true --this variable is used to control the flow
  		
  		--some variables used in the methods below
  		local arrObject = undefined
  		local strPath = getDir #temp
  		local outputFolder = undefined
  		
  		if proceed do proceed = fn_setupObjects &arrObject &strMessage 
  		if proceed do proceed = fn_prepObjects &arrObject &strMessage threshold:threshold
  		if proceed do proceed = fn_prepOutputLocation strPath &outputFolder &strMessage
  		if proceed do proceed = fn_saveObjects arrObject outputFolder &strMessage
  		
  		format "%" (strMessage as string)
  	)
  	clearListener()
  	event_export threshold:200
  )

In the event_export method I can break the flow by setting one of the proceed values to false. Either one of the methods does it himself, or during development I can insert it myself. This really works for me at the moment.

i also always try to design my tool as ‘one tool – one structure – one file’. of course all my tools are sharing common libraries, but it’s different story.

for function naming i always use camel-case started with lower case. never use any spacial prefix.
structures i name camel-case started with upper case
variables and parameters i name usually lower case with using underscore or camel-case with one hump maximum

 JHN

Same here, fn and lots of camelCase, also I’m looking at the ECMA coding standards for c#.
fn simply because it’s shorter, further a lot of very descriptive fn names. Lots of get/set names. I do not prefix a fn with fn_ a function name should be descriptive in itself, I try to properly order my variables and fn’s.

-Johan

I did lots of Maxscript 1998-2002, but I can’t remember what I used back then.

Then I did lots of MEL for a few years, where a procedure was a “proc”. When I came back to maxscript in 2008, I guess I just kept the paradigm since “fn” is more like “proc” than “function” is.

“fn” is also used more than “function” is in the mxs reference.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

you are right. you reminded me the main reason why i switched from ‘function’ to ‘fn’ in 2002… i’ve just returned back to max from maya with its ‘proc’ used with MEL.
now everything looks for me consistent:
mxs: fn instead of function
mel: proc instead of procedure
python: def instead of define (or definition)

Always interesting to read other’s opinions/experiences on coding standards.

     When I started to get into maxscript in 2005 with no programming knowledge of any kind, my scripting in general was very... messy with no consistency.
   
     I Still don't have much programming knowledge outside of maxscript, but I tend to be much more structured and consistent. For functions, I always use "fn", short and clear.  I just try to give them a name that is as self-explanatory as possible and without any specific prefix or suffix. 

Also, since I've read denisT's post on "one tool, one global" some time ago, I've learn about structures and tried to understand them more (this was all new to me) and converted some of my most used tools inside structures and try to do so for every new tool I create now.
Page 3 / 4