Self can only be used in Methods?

BlitzMax Forums/BlitzMax Programming/Self can only be used in Methods?

H&K(Posted 2007) [#1]
Why does it give this error? When its quite possible to use Self within member Functions, as long as you only self.AGlobalofTheType

A Better error message would be, "Compile Error: Self cannot be envoked here"


FlameDuck(Posted 2007) [#2]
Self is a reference to the current object. Functions are "static" references and as such do not have a current object associated with them. You get the same error in every other language if you mix and match static and non-static references.


H&K(Posted 2007) [#3]
Self is a reference to the current object. Functions are "static" references and as such do not have a current object associated with them
And?
My point is that you can use self in a function, but if you use it wrong in a function, the error tells you that you cannot use it in a function at all. Which would, if you didnt know lead you to think that you cannot use self in a function. But you can, as long as you only referance to other member functions or Globals of the type.

Ok, you dont need to use self, as the functions/globals dont need a type identification, but I use self (Or the type name) all the time to get the intelisence popup


SculptureOfSoul(Posted 2007) [#4]
Self shouldn't be used with a function for the reason FlameDuck mentioned. If it is allowed, well, that's up to Mark I guess, but it should spit out an error as there is no logical instance to associate a "self" with within a function (unless the language offers generic functions ala Lisp or some similar construct.)

I mean, what does it mean to say "self" within a function? A particular object is not calling the function, the function is being called on an object or objects (or any # of parameters.)

I'd hate to have to read code that had selfs all over the place in functions. It just doesn't make any sense.


H&K(Posted 2007) [#5]
It makes sence when you are calling member function or Global that are associated with the type and not with an instance.

'		-----------------------------------------------------------------------------------
Type TDisplay
'				--------------------------------------------------------------------
	Global	GF_TheDeskTop	:TGadget	= Desktop ()
	Global	GF_DeskTopSize	:TIntPair	= TIntPair.RF_Create(GadgetWidth (TDisplay.GF_TheDeskTop),..
									GadgetHeight(TDisplay.GF_TheDeskTop))
'				--------------------------------------------------------------------
	Global	GF_WindowSize	:TIntPair	= TDisplay.RF_WindowSize()	
	Global	GF_MainWindow	:TGadget	= TDisplay.RF_CreateWindow()
'				--------------------------------------------------------------------															 
	Global	GF_Pane		:TGadget	= Tdisplay.RF_CreatePane()
	Global	GF_PaneSize	:TIntPair	= TIntPair.RF_Create(GadgetWidth(TDisplay.GF_Pane),..
									GadgetHeight(TDisplay.GF_Pane))
	Global	GF_PaneMulti	:TFloatPair	= TFloatPair.RF_Create(	TDisplay.GF_PaneSize.F_X/100.0,..
									TDisplay.GF_PaneSize.F_Y/75.0)
'				--------------------------------------------------------------------	
	Function RF_WindowSize:TIntPair()
	
		If C_DevBuild = True
			Return New TIntPair.RF_Create(400*C_DevBuildSize,300*C_DevBuildSize)
		Else
			Return Self.GF_DeskTopSize.RM_Copy()
		EndIf

	EndFunction
'				--------------------------------------------------------------------
	Function RF_CreateWindow:TGadget()
		
		Return CreateWindow("Game Window",..
				   (Self.GF_DeskTopSize.F_X-Self.GF_WindowSize.F_X)/2 ,..
				   (Self.GF_DeskTopSize.F_Y-Self.GF_WindowSize.F_Y)/2 ,..
				   Self.GF_WindowSize.F_X ,..
				   Self.GF_WindowSize.F_Y ,..
				   Null,..
				   WINDOW_CLIENTCOORDS							)
	
	End Function
'				--------------------------------------------------------------------
	Function RF_CreatePane:TGadget()

		Local Temp:TGadget	= CreateCanvas(	0,..
							0,..
				                        Self.GF_WindowSize.F_X,..
				                        Self.GF_WindowSize.F_Y,..
				                        Self.GF_MainWindow 			)
		ActivateWindow( Temp )
		RedrawGadget( Temp )
		Return Temp
	
	End Function
'				--------------------------------------------------------------------
End Type
'		-----------------------------------------------------------------------------------

I'd hate to have to read code that had selfs all over the place in functions.
Well you would hate my code, cos as I said I have self all over the place, cos then I get the Intelisence popup, and dont need to remember any names.


SculptureOfSoul(Posted 2007) [#6]
Self isn't needed in the instances you listed. All it does is further obscure the meaning of the code. Self means "the instance invoking the method" - and when used as you do all it does is make it harder to understand what you are saying, and makes the code that much more verbose.

If you want to use it for intellisense you should go back and delete the selfs afterwards.


H&K(Posted 2007) [#7]
Self isn't needed in the instances you listed

Ok, you dont need to use self, as the functions/globals dont need a type identification, but I use self (Or the type name) all the time to get the intelisence popup

If you want to use it for intellisense you should go back and delete the selfs afterwards
Why? Ive already made sure that it doesnt slow down the code. And its only your opinion that it makes it harder to read. I personaly prefer it, cos then I know its a member Function/Global and not an ordinary Function/global

Self means "the instance invoking the method"
This entire thread is me saying that it doesnt mean that. It also means this Type for static members.


sswift(Posted 2007) [#8]
I'm gonna have to agree with those guys. You might have your resons for using it, but I look at the above code and I have no idea what's going on. If you ever plan to have someone else look at your code, I'd suggest not doing that.

If you say, licensed someone's lib, and were using it, and then wanted support they'd have a hell of a time deciphering your code to help you find the bug, for example.

But if you think this is a bug then this should be in the bug forum, not the discussion forum. :-)


H&K(Posted 2007) [#9]
but I look at the above code and I have no idea what's going on
But that cannot be because of the use of self? Thats just cos you dont have any idea what's going on. All self is doing is making the global names a bit longer. So if you had said, "It makes it harder to see whats going on", then fair enough. If you just remove the .
ie SelfGF_Windowsize, then would it be harder to understand or easyer?


sswift(Posted 2007) [#10]
Well sure, if you tell me that, then I could read it, but I wouldn't have known five minutes ago that that's how it behaves. (And if you ask me in a month I'll have forgotten!)

But I could also have written this in my code:
Roll# = Min(Abs(Vroll#), 800)/800.0 * Sgn(Vroll#)

Which you might argue is perfectly readable.

But I'd disagree. So after I wrote that, I scrapped it and rewrote it like so:

Roll# = Vroll# / 800.0
If Roll# < -1 Then Roll# = -1
If Roll# > 1 Then Roll# = 1

And it's a lot more obvious this way what the code is doing, or at least what the output will be.

Using Self as you are might be perfectly obvious to you. And if I commented my code, and nobody else ever looked at it, the first solution maybe would have been fine. But I always strive to make my code as readable by humans as possible, and using Self in a way that nobody else does goes against that philosophy.

As a side note, with all the people who've licensed my libraries, I've never once had someone say my code was hard to read. :-)


H&K(Posted 2007) [#11]
But I always strive to make my code as readable by humans as possible, and using Self in a way that nobody else does goes against that philosophy. :-)
True, and Ive never posted any code with self in this way before, (I have in Methods), My point is that the error message "Compile Error: Self can only be used in Methods" is wrong, because it can also be used to access static members whilst in Functions.

I take your point about support, but whenever I ask for Help I remove all the GF_s and RM_s and stuff (My form of Hungarian Notation), but I do use self (or the Type Name) whenever I am accessing a member of the type, irrelevent of if it needs to be used or not. So maybe Im the only one who would notice this. And maybe it is a bug. The only reason I noticed today was because I moved the globals from Tgame to Tdisplay, and the used to be TGame.etc and I just without thinking did a search replace for TGame to Self without thinking.

GF_Roll:Float = GF_Vroll / 800.0
If GF_Roll < -1 Then GF_Roll = -1
If GF_Roll > 1 Then GF_Roll = 1



Michael Reitzenstein(Posted 2007) [#12]
I too think H&K's code is horrible to read, but

This entire thread is me saying that it doesnt mean that. It also means this Type for static members.


He's entirely right. According to the docs, Self is a 'reference to the current object', but that isn't consistant with the way the language treats it. It is also entirely logical for Self and Super to take on a different meaning in a static context, and it is actually more than syntatic sugar. Self could be used to instantiate a new object, for instance.


sswift(Posted 2007) [#13]
I've been using hungarian-like notation for a while now, for example, IMG_Ship, but I've started to experiment with notation like Ship_Image and Ship_Sprite.

Of course I shouldn't even have Ship_Image and Ship_Sprite cause they're in my Ship type, and I should just have Ship.Image, but I also had a thruster image in the type too and using Sprite as a field name makes me uncomfortable since Sprite is also the type of the field. Maybe I should have used TSprite for my sprite system type, but I rather like saying Sprite.Create() in my code. And so far BlitzMax seems to be able to handle Sprite = Sprite.Create() just fine.

Also, sometimes I kinda wish that I could do stuff like have the same variable name with different types. So I could do this:

Ship = LoadImage()
Ship = Sprite.Create()

Now if I could do that, then what I would actually do on most occasions is write it like so:

Ship:TImage = LoadImage()
Ship:Sprite = Sprite.Create()

But instead I'm stuck with ugly code like this:

Field Ship_Image:TImage
Field Ship_Sprite:Sprite

But then I'd have to figure out what to do when I've got

Type Ship
Field Sprite:Sprite
End Type

Cause no way do I want to put Sprite:Sprite = Sprite.Create() in my methods!

So I guess I will continue to experiemnt with my notation, finding better ways that make it easier to read. Less typing is less of a concern for me since I comment my code so much. Verbose variable names would actually allow me to cut down on my comments a lot. And if they make the code easier to read, and by that I mean my eyes don't hurt looking at a page of ALLMYCONSTANTSINCAPSWITHNOSPACES, then that's great.


Michael Reitzenstein(Posted 2007) [#14]
Useful hungarian notation: http://www.joelonsoftware.com/articles/Wrong.html


sswift(Posted 2007) [#15]

In general, I have to admit that I’m a little bit scared of language features that hide things. When you see the code

i = j * 5;

… in C you know, at least, that j is being multiplied by five and the results stored in i.

But if you see that same snippet of code in C++, you don’t know anything. Nothing. The only way to know what’s really happening in C++ is to find out what types i and j are, something which might be declared somewhere altogether else. That’s because j might be of a type that has operator* overloaded and it does something terribly witty when you try to multiply it. And i might be of a type that has operator= overloaded, and the types might not be compatible so an automatic type coercion function might end up being called. And the only way to find out is not only to check the type of the variables, but to find the code that implements that type, and God help you if there’s inheritance somewhere, because now you have to traipse all the way up the class hierarchy all by yourself trying to find where that code really is, and if there’s polymorphism somewhere, you’re really in trouble because it’s not enough to know what type i and j are declared, you have to know what type they are right now, which might involve inspecting an arbitrary amount of code and you can never really be sure if you’ve looked everywhere thanks to the halting problem (phew!).

When you see i=j*5 in C++ you are really on your own, bubby, and that, in my mind, reduces the ability to detect possible problems just by looking at code.




I love this man! In a purely platonic way of course.


H&K(Posted 2007) [#16]
Sprite:Sprite = Sprite.Create()
(This is jus the way I do it, its not better, just the way I do it)

The first sprite, Is lets assume a field of a Type, if so it would be, F_Sprite, The second Sprite Is a Type, TSprite as is the third. And Create is a return Fucntion.

 Field F_Sprite:TSprite = TSprite.RF_Create()
or. The first Sprite, is a global
Global G_Sprite:TSprite = TSprite.RF_Create()

So we do have a fundimental difference of Opinion, because the thing that you will noway have, is in fact my preffered way.
In your other example, I would have,
Type TShip
Field F_Image:TImage
Field F_Sprite:Tsprite
...

For Local A_Ship:TShip = 0 to Eachin TShip.GF_List
A_Ship.F_Image = etc
A_Ship.F_Sprit = etc
next

C_ Const
G_ Global
P_ Paramater
T Type
RF_ A Function that returns somthing
RM_ A Method that returns something
SM_ A Method that doesnt return anything
SF_ Same for Fucntions
GF_ Global Field
F_ Field
L_ or A_ A local instance so
Self.GF_DeskTopSize.F_X
Self is this (TDisplay) type because
GF_DeskTopSize is a static Global Field
F_X is a member Field of GF_DeskTopSIze
Maybe
TDisplay.GF_DeskTopSize.F_X
Would be easyer to read, but as I said Ive just moved it from TGame to TDisplay, and it seemed better to change it to Self, incase I moved it back


grable(Posted 2007) [#17]
Personally i dont use Self (or the typename) unless there is a naming conflict.


ImaginaryHuman(Posted 2007) [#18]
I don't use self at all, assuming it only applied to Methods and that a function has no idea what local data instance you want to associate with. You would access the function as mytype.function() whereas you'd access a method with myinstance.method - I generally wouln't try to confuse the two.


bradford6(Posted 2007) [#19]
if you want to use an Instance of an Object in a function, just pass it in.

function foobar:TThingy( myOb:Tfruit )

myOb.attribute = something
end function


Curtastic(Posted 2007) [#20]
I think the self's help a lot inside functions. Without the self, you might not know whether the variable is global or is inside the type.


WendellM(Posted 2007) [#21]
Michael Reitzenstein wrote:
Useful hungarian notation: www.joelonsoftware.com/articles/Wrong.html

That's a great piece, thanks for the pointer. It explains why Apps Hungarian really is useful and explains how it "devolved" into the largely useless Systems Hungarian (with links at the bottom for more detail).

Several other good articles on that site, too, which I'm now going through.


Gabriel(Posted 2007) [#22]
I love these discussions. They're completely worthless :P

In the kind of solo and indie project most of us are working on, code needs to be readable to one and only one person. If making all your type names all caps and all your field names have a number in the middle makes it more readable to you, do it.

Personally ( For what it's worth, I assume nothing ) I use self to get the intellisense popup and delete it later, unless it's a longish method and I want to make it clear what are member fields and what are local variables.

I also agree with H&K that it's preferable to edit your code before asking for help rather than constrict yourself to a coding style you don't favour just for those instances. I rather suspect I'm going to be spending a lot less time reading his methods than he is, so he should present them for himself.

Oh, and I agree with Michael regarding the purpose of self in a static function.