Are dynamic structs possible? Reopen


#1

Hi,

I reopen this post because it was not a bad idea.

Sometime I work in Adobe Flash Actionscript3.
And I like :
-extending classes
-is well organized and you can call them easily

It will be good to have something like this in Maxscript

Because is not easy task , I tried one different way for now :slight_smile:

  1. load all desired structures at max start
  2. create master structure which will call any of function you wish to execute

basic idea is to have each class in separate file but instead of extending it
create new function in other file.

after that have one master structure which will call any of you function
like master.reverseArray #(1,2,3)

this should make programing more easy, whatever better idea will be welcome :slight_smile:msx_app.rar (1.7 KB)

Struct STRUCTURE_COLLECTION_MANAGER (
	
public
	app_dir = "",
private
	ini_file = app_dir + "Struct_List.ini",
	struct_names = #(), --collect structure names here
	fn loadMyStructures = (

		if not doesFileExist ini_file do return false
		local struct_files = getINISetting ini_file "STRUCTURES"
		for file_name in struct_files do (

			local struct_name  = getINISetting ini_file "STRUCTURES" file_name
			struct_names += #(struct_name)
			fileIn (app_dir + file_name + ".ms")
		)
		OK
	),
	on create do (loadMyStructures()),
public
	fn run fn_str params:#() = (
		
		format "SCM > Run > fn:% params:% cnt:%\n" fn_str params params.count
		if classOf fn_str != String or classOf params != Array do  return false
		for s in struct_names do (
			
			local struct_instance = execute s
			if not (hasProperty struct_instance fn_str) do continue --skip structures without desired function
			local prop = getProperty struct_instance fn_str
			local result  = case params.count of (

				0: prop ()
				1: prop params[1]
				2: prop params[1] params[2]
				3: prop params[1] params[2] params[3]
				4: prop params[1] params[2] params[3] params[4]
			)
			return result
		)
		false
	)
)
GLOBAL scm = STRUCTURE_COLLECTION_MANAGER app_dir:"C:\\temp\\msx_app\\"

/*
	--first load all structures and collect struct instance names
	--second run any of you functions by one root command
	--@Example
	abc = #("c", "b", "a")
	scm.run "reverseArray" params:#(abc)
	--@Output 	#("a", "b", "c")
*/

#2

let’s talk about the reason first…

as i understand you want to put all generally used methods under one structure. … but you want originally define them in different structures (a la classes).

my objection N1:
when you design a class you also design this class name to give the sense to the name
when you design methods you do the same
the combination of both should give you the perfect sense and minimized length of final call…

check

we have an Array class (struct) collection… it make sense to name the class ArrayOps (or like that)
we have methods by meaning - Reverse Array, Merge Arrays, Filter Arrays, Intersect Arrays, ect…
we can name these methods by their meaning as there are they going

but we already have the class name with which together the names will get some ā€˜unnecessary details’. it makes more sense to name them like:
ArrayOps.Reverse
ArrayOps.Merge
ArrayOps.Filter
ArrayOps.Intersect

any user can get it by name

If you put these methods into abstractly named general class (like Master) the names of array methods will lose the sense (at least they will not be clear anymore). Capiche?


#3

let’s continue talking about Advantages and Disadvantages…

many times methods defined into struct (class) belong to this class by using, and share another methods from this class…

in MXS the only way to share another methods from the struct is to work inside an instance of this struct vs its definition. There is another problem here.
MXS doesn’t give you a chance to know is it a class method or static method. So you need to specially ā€˜mark’ your methods (using a naming convention for example) to be able collect the right ones


#4

Hi Denis, it is nice to hear you again, after many ears :slight_smile:
You right, merge all structures may slow programming…
For now I’m using old way
image
at begin It was one idea… how to implement method of extending structures
I don’t know how is happen I make something totally different :smiley:


#5

and nonetheless… let’s return to your idea.

the task itself doesn’t make sense fort me, but it has an interesting technical element that i want to play with… :slight_smile:

THE DYNAMIC STRUCT POSSIBILITY


#6

i was here all the time… but where were you all these ears :slight_smile: ?


#7

I was moved on another project to make Interactive books for the children.
Most time I spend to learn acrtionscript3 in Adobe Flash.
It was good 5 years experience.
image
I love the class structures which is in my opinion much better than in max-script :slight_smile:
And now I’m back in my old company 2K Czech.
It is time for resurrecting Micra Tools which is helped me a lot in past :smiley:


#8

So Welcome back! :slight_smile:


#9

when I look my old scripts, the first idea it was to drop it and make it all from begin :smiley:
And now when is almost done I’m trying to fetch some features from action-script in to max-script
like event handler functions (live update)

mcEvents.registerEvent ā€œVariableChangedā€ form.varChanged
mcEvents.dispatchEvent ā€œVariableChangedā€ data:1
mcEvents.unregisterEvent ā€œVariableChangedā€ form.varChanged


#10

it’s a good idea

each time I rewrite my old tool, it becomes at least three times smaller and five times faster


#11

Thanks Man, good night and Happy new year 2019 :smiley:


#12

It’s not the same, but… how about this?

	Struct STRUCTURE_COLLECTION_MANAGER
	(
		private
		globalStructs,
		globalStNames,
		ID,

		public
		_,
		fn setStruct structID =
		(
			if isKindOf structID integer do
			(
				ID = structID
				_ = globalStructs[ID]
				return globalStNames[ID]
			)
			if isKindOf structID StructDef do
			(
				_ = structID
				ID = findItem globalStructs structID
				return globalStNames[ID]
			)
			if isKindOf structID name or  isKindOf structID string do
			(
				structID = structID as name
				ID = findItem globalStNames structID
				_ =  globalStructs[ID]
				return globalStNames[ID]
			)
		),
		fn current = globalStNames[ID], 
		on create do
		(
			-- You can fill here the arrays with your method reading from an INI file
			globalStructs = #(MY_ARRAY_STRUCTURE, MY_MATH_STRUCTURE)
			globalStNames = #(#arrayOps, #mathOps)
			-- Default value:
			ID = 1
			_ = globalStructs[ID]
		)
	)
	GLOBAL SCM = STRUCTURE_COLLECTION_MANAGER()
	
	/*
	-- Use:
	SCM._.reverseArray #(1,2,3)
	SCM.current()
	SCM.setStruct #mathOps
	scm._.isInteger 4
	scm.setStruct 1
	a=#(1,2,3); scm._.removeItem a 3; a
	scm.setStruct MY_MATH_STRUCTURE
	scm._.roundToInt 25.45 10
	*/

EDIT: Happy New Year!! :santa:


#13

Nice one andres!, Happy year too :smiley:
You script is another angle of view :smiley:
I think we are more close now…

I’m sorry for starting this topic from end, wee need to start at beginning :wink:
one example of dynamic structure (in Flash called Class)
I will show it in actionscript language for better understanding

  1. [package classes] this header shown directory location of this class
    @example: D:\work\my_project\classes*.*
  2. [public class Person] this like in maxscript --> Struct person ()
package classes
{
    public class Person
    {
        // Properties.
        public var _age:Number;
        public var _name:String;

        // Constructor.
        public function Person(age:Number, name:String)
        {
           _age = age;
           _name = name;
        }
    }
}
@usage
import classes.Person;
var marty:Person = new Person(24, "Marty");
trace (marty._age) // 24
  1. now we gonna to extend class Person and make new Class --> Person_Mage
package classes // we can stay in same directory
{
    public class Person_Mage extends Person
    {
        // add some new property
        public var _inteligence:Number;

        // Constructor.
        public function Person_Mage (age:Number, name:String, inteligence:Number)
        {
           _age = age;
           _name = name;
           _inteligence = inteligence;
        }

        // Create person mage function
        public function throwFireball(target:Point):Bollean
        {
           if inteligence > 50 then trace("You hit target!") else trace("You miss....")
           return inteligence > 50 
        }
    }
}
@usage
import classes.Person_Mage ;
var marty:Person_Mage = new Person_Mage (24, "Marty", 80);
trace (marty.throwFireball(pos_x, pos_y, pos_z)) // "You hit target!"

I dot know if this is the best example but extending mechanic is visible :slight_smile:


#14

here is one maxscript example

  1. Base Dotnet Form Struct
Global mcBaseForm
if ::mcBaseForm != undefined do try(mcBaseForm.Close())catch()
(
	struct NET_FN (
		
		fn netRect pos size   = (dotnetObject "Drawing.Rectangle" pos.x pos.y size.x size.y),
		fn netColor clr       = ((dotNetClass "Drawing.Color").fromArgb clr.r clr.g clr.b)
	)
	local mcs, dia, net = NET_FN()
	local mcs, dia
	struct DOTNET_FORM_BASE (

		-- Default Properties
		form = dotNetObject "MaxCustomControls.Maxform",
		lblT      = dotNetObject "label",
		tlp        = dotNetObject "TableLayoutPanel",
		form_size,
		form_color,
		debug = 0,

		-- Default Functions
		fn maxHW = (
		
			local hv = DotNetObject "NativeWindow"
			hv.AssignHandle (DotNetObject "System.IntPtr" (Windows.GetMaxHWND())) 
			return hv
		),
		fn close = (dia.close()),
		fn changeBackcolor s a = (s.backColor = net.netColor mcs.form_color),

		-- SetUp Interface
		fn init pos:[400, 350] size:[350, 250] backcolor:yellow title:"Max Form" = (
			
			form_size = size
			form_color = backcolor
			
			form.text = title
			form.StartPosition = form.StartPosition.Manual
			form.bounds = net.netRect pos size
			
			-- Default Events
			dotnet.AddEventHandler form "BackColorChanged" changeBackcolor --override backcolorchanged event (without this form color is default)
			
			local hv = maxHW ()
			form.show(hv) -- Shows the form with the specified owner (MAX) to the user (creatd by lo)
			hv.ReleaseHandle()
			OK
		),
		initIt = init pos:[400, 350] size:[350, 250] title:"My Form 1 v0.01"
	)
	mcBaseForm = DOTNET_FORM_BASE()
	mcs = mcBaseForm --structure shortcut (simplest use)
	dia = mcBaseForm.form --form instance
)
  1. and here is ā€œextended versionā€ (is rewritten from begin)
    should be an extension because is have all like in base (but how to do this?) :wink:
Global mcCompactForm
if ::mcCompactForm != undefined do try(mcCompactForm.Close())catch()
(
	struct NET_FN (
		
		fn netRect pos size   = (dotnetObject "Drawing.Rectangle" pos.x pos.y size.x size.y),
		fn netColor clr       = ((dotNetClass "Drawing.Color").fromArgb clr.r clr.g clr.b),
		fn mcFormSnap form pos = (
			
			local newpos = mouse.screenpos - pos
			local net_pos =  dotnetObject "Drawing.Point" newpos.x newpos.y
			form.location = net_pos
		)
	)
	local mcs, dia, net = NET_FN()
	struct DOTNET_FORM_BASE (

		-- Default Properties
		form = dotNetObject "MaxCustomControls.Maxform",
		lblT      = dotNetObject "label",
		tlp        = dotNetObject "TableLayoutPanel",
		netDmPos, --mouse pos on dialog
		form_size,
		form_color,
		bar_height      = 14,
		border_offset  = 2,
		debug = 0,

		-- Default Functions
		fn maxHW = (
		
			local hv = DotNetObject "NativeWindow"
			hv.AssignHandle (DotNetObject "System.IntPtr" (Windows.GetMaxHWND())) 
			return hv
		),
		fn close = (dia.close()),
		fn changeBackcolor s a = (s.backColor = net.netColor mcs.form_color),
		--Move / Snap Dialog
		fn onLblTMouseMove s a = ( if a.Button == a.Button.left do  net.mcFormSnap dia mcs.netDmPos), --drag form
		fn onLblTMouseDown s a = ( --start drag
				
			dia.cursor.current = netCursors.Hand
			if a.Button == a.Button.left do ( --enable drag
				mcs.netDmPos = [dia.MousePosition.x, dia.MousePosition.y] - [dia.left, dia.top]  
			)
		),
		fn onLblTMouseUp s a = (if a.Button == a.Button.right then mcs.close()), --stop drag or close
		-- Custom  Functions
		
		-- SetUp Interface
		fn init pos:[400, 350] size:[350, 250] backcolor:yellow forecolor:white toolbarcolor:blue title:"Max Form" = (
			
			form_size = size
			form_color = backcolor
			
			form.text = title
			form.ControlBox  = false --hide main bar
			form.ShowInTaskbar = false
			form.StartPosition = form.StartPosition.Manual
			form.bounds = net.netRect pos size
			form.FormBorderStyle = form.FormBorderStyle.none
			form.BackColor = net.netColor backcolor
			form.opacity = 1
			
			--toolbar
			lblT.bounds = net.netRect [border_offset, border_offset] [form_size.x - border_offset*10 , bar_height]
			lblT.BackColor = net.netColor toolbarcolor
			lblT.ForeColor = net.netColor forecolor
			lblT.Text = title
		
			--Componnts Layout
			tlp.Bounds  = net.netRect [border_offset, bar_height + border_offset * 2] [form_size.x - 20, form_size.y - 36]
			tlp.backColor = net.netColor backcolor
			
			-- Default Events
			dotNet.addEventHandler lblT   "MouseMove" onLblTMouseMove
			dotNet.addEventHandler lblT   "MouseDown" onLblTMouseDown 
			dotNet.addEventHandler lblT   "MouseUp" onLblTMouseUp
			dotnet.AddEventHandler form "BackColorChanged" changeBackcolor --override backcolorchanged event (without this form color is default)
			
			--Add Controls
			form.controls.addRange ( #(tlp, lblT)  )
			local hv = maxHW ()
			form.show(hv) -- Shows the form with the specified owner (MAX) to the user (creatd by lo)
			hv.ReleaseHandle()
			OK
		),
		initIt = init pos: [800, 350] size:[350, 250] title:"My Form 2 v0.01"
	)
	mcCompactForm = DOTNET_FORM_BASE()
	mcs = mcCompactForm --structure shortcut (simplest use)
	dia = mcCompactForm.form --form instance
)

second structure should be extension from the first one


#15

That seems more a matter of inheritance than of dynamic class.
Really hard to imagine how to do it.


#16

Without any usability, but fun … (just to start the new year :slight_smile: )

[code]

struct parentStruct
(
	-- Public Struct Data and Functions
	parentVar_01,
	parentVar_02 = 5,
	parentVar_03 = "Hello",
	fn parentFN_01 = parentVar_01 * parentVar_02,
	fn parentFN_02 data = data * 3 * this._parentVar_01,
		
	
	-- FOR INHERITANCE
	-------------------------------------------------
	-- Inherit Functions (Fixed, always the same for parent and children)
	fn _getHeader = this.stHeader,
	fn _getPublic = this.stPublic,
	fn _getPrivate = this.stPrivate,
	fn _getClose = this.stClose,
	-------------------------------------------------
	
	-------------------------------------------------
	-- Fixed Inherit Function ONLY for first parent
	fn _createDerivedClass child=
	(
		txtPublic = this.stPublic + child._getPublic()
		txtPrivate = this.stPrivate + child._getPrivate()
		txtClose = this.stClose + "\n" + child._getClose()
		
		txt = "struct " + child._getHeader() + "("
		txt += txtPublic
		txt += this.stInheritFN
		txt += "private " + txtPrivate
		txt += "stHeader = \"" + child._getHeader() + "\","
		txtPublic = substituteString txtPublic "\\" "\\\\"
		txtPublic = substituteString txtPublic "\"" "\\\""
		txt += "stPublic = \"" + txtPublic + "\","
		txtPrivate = substituteString txtPrivate "\\" "\\\\"
		txtPrivate = substituteString txtPrivate "\"" "\\\""
		txt += "stPrivate = \"" + txtPrivate + "\","
		fixtxtClose = substituteString txtClose "\\" "\\\\"
		fixtxtClose = substituteString fixtxtClose "\"" "\\\""
		txt += "stClose = \"" + fixtxtClose + "\","
		fixstInheritFN = substituteString this.stInheritFN "\\" "\\\\"
		fixstInheritFN = substituteString fixstInheritFN "\"" "\\\""
		txt += "stInheritFN = \"" + fixstInheritFN + "\","
		txt += "on create do (" + txtClose + "))"
		derivedClass = execute txt
	),
	--------------------------------------------------------
	
	private
	-- Private Struct Data and Functions
	_parentVar_01 = 10,
	
	
	-- FOR INHERITANCE
	------------------------------------------
	-- Data needed for inheritance
	-- Must fill for each parent and child (it's a copy of struct definition)
	stHeader = "parentStruct",
	stPublic =
	"
	parentVar_01,
	parentVar_02 = 5,
	parentVar_03 = \"Hello\",
	fn parentFN_01 = parentVar_01 * parentVar_02,
	fn parentFN_02 data = data * 3 * this._parentVar_01,
	",
	stPrivate =
	"
	_parentVar_01 = 10,
	",
	stClose = "",

	--------------------------------------
	-- Fixed data and functions ONLY for first parent
	stInheritFN =
	"
	fn _getHeader = this.stHeader,
	fn _getPublic = this.stPublic,
	fn _getPrivate = this.stPrivate,
	fn _getClose = this.stClose,
	
	fn _createDerivedClass child=
	(
		txtPublic = this.stPublic + child._getPublic()
		txtPrivate = this.stPrivate + child._getPrivate()
		txtClose = this.stClose + \"\\n\" + child._getClose()
		
		txt = \"struct \" + child._getHeader() + \"(\"
		txt += txtPublic
		txt += this.stInheritFN
		txt += \"private \" + txtPrivate
		txt += \"stHeader = \\\"\" + child._getHeader() + \"\\\",\"
		txtPublic = substituteString txtPublic \"\\\\\" \"\\\\\\\\\"
		txtPublic = substituteString txtPublic \"\\\"\" \"\\\\\\\"\"
		txt += \"stPublic = \\\"\" + txtPublic + \"\\\",\"
		txtPrivate = substituteString txtPrivate \"\\\\\" \"\\\\\\\\\"
		txtPrivate = substituteString txtPrivate \"\\\"\" \"\\\\\\\"\"
		txt += \"stPrivate = \\\"\" + txtPrivate + \"\\\",\"
		fixtxtClose = substituteString txtClose \"\\\\\" \"\\\\\\\\\"
		fixtxtClose = substituteString fixtxtClose \"\\\"\" \"\\\\\\\"\"
		txt += \"stClose = \\\"\" + fixtxtClose + \"\\\",\"
		fixstInheritFN = substituteString this.stInheritFN \"\\\\\" \"\\\\\\\\\"
		fixstInheritFN = substituteString fixstInheritFN \"\\\"\" \"\\\\\\\"\"
		txt += \"stInheritFN = \\\"\" + fixstInheritFN + \"\\\",\"
		txt += \"on create do (\" + txtClose + \"))\"
		derivedClass = execute txt
	),
	",
	-------------------------------
	
	on create do ()
)
parentStruct = parentStruct()



struct ChildStruct
(
	childVar_01,
	childVar_02 = 7,
	fn childFN_01 = childVar_01 * childVar_02,
		
	-- FOR INHERITANCE
	-------------------------------------------------
	-- Inherit Functions (Fixed, always the same for parent and children)
	fn _getHeader = this.stHeader,
	fn _getPublic = this.stPublic,
	fn _getPrivate = this.stPrivate,
	fn _getClose = this.stClose,
	-------------------------------------------------
	
	private
	
	-- FOR INHERITANCE
	------------------------------------------
	-- Data needed for inheritance
	-- Must fill for each parent and child (it's a copy of struct definition)
	stHeader = "ChildStruct",
	stPublic =
	"
	childVar_01,
	childVar_02 = 7,
	fn childFN_01 = childVar_01 * childVar_02,
	",
	stPrivate = "",
	stClose =
	"
	print childVar_02
	print \"Creating\"
	",
	------------------------------------------
	
	on create do
	(
		print childVar_02
		print "Creating"
	)
)
ChildStruct = ChildStruct()


completeChildStruct = parentStruct._createDerivedClass ChildStruct
completeChildStruct = completeChildStruct()



struct subChildStruct
(
	subchildVar_01 = 55,
		
	-- FOR INHERITANCE
	-------------------------------------------------
	-- Inherit Functions (Fixed, always the same for parent and children)
	fn _getHeader = this.stHeader,
	fn _getPublic = this.stPublic,
	fn _getPrivate = this.stPrivate,
	fn _getClose = this.stClose,
	-------------------------------------------------
	
	private
	_subchildVar_01 = 66,
	
	-- FOR INHERITANCE
	------------------------------------------
	-- Data needed for inheritance
	-- Must fill for each parent and child (it's a copy of struct definition)
	stHeader = "subChildStruct",
	stPublic =
	"
	subchildVar_01 = 55,
	",
	stPrivate = 
	"
	_subchildVar_01 = 66,
	",
	stClose =
	"
	",
	------------------------------------------
	
	on create do
	(
	)
)
subChildStruct = subChildStruct()

RecompleteChildStruct = completeChildStruct._createDerivedClass subChildStruct
RecompleteChildStruct = RecompleteChildStruct()

[code]


#17

hi Andres,
your script looks promising. :slight_smile:
it will take some time for me to explore it.