[RESOLVED] PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Hello
can you tell me the differences between
PUBLIC property Let / Get and
FRIEND property Let / Get ?
I'm interested because I noticed (especially for Function and Sub) that FRIEND makes the compiled program faster.
I have noticed that in some cases FRIEND can raise errors (even if is used only in 1 project).
But I still don't understand why (the cases where) it happens.
I thank in advance those who can give clear explanations, maybe with the addition of functioning and non-functioning examples.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
A simple (even stupid sounding) partial answer is that Friend members are not part of the public interface of the class. But it means the calls are "thinner" without the overhead required of Public members. Probably close if not identical to calling Public members of a static (BAS) module.
The details are probably less important than knowing this is a way to avoid exposing internal-use members to external clients. That makes them most useful in a DLL, OCX, or ActiveX EXE.
The performance issue is really a side effect. In theory I'm not sure we're supposed to count on them for that, because in future versions of VB they might be implemented differently. So much for that, we'll never see a new VB.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
I'm sure others will chime in regarding speed differences, exposure outside of your project, UDT parameters, and more.
Here is something that Friend allows but is not as obvious.
Implemented interfaces. Typically one creates a class to be implemented. That class contains just public methods to be implemented. That type of interface typically has no code. However, you can create a class that has Public methods to be implemented and also Friend methods that can be called and has code. This allows a user to implement and instantiate a class instance using the same class...
Code:
Implements IMyCustomInterface
Dim myCustInf As IMyCustomInterface
Private Sub Form_Load
Set myCustInf = New IMyCustomInterface
' in this scenario, the IMyCustomInterface might have a Friend method that accepts the
' form as a parameter if the form wants to use implementation. The class then knows if it
' is created just for its Friend methods or Friend & implemented methods
End Sub
The user can opt to just implement or instantiate for the friend methods or both. That type of setup can be useful if it fits. Just another tool in the shed.
Insomnia is just a byproduct of, "It can't be done"
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Hi reexre,
As you've probably discovered, Friend is only allowed in a class module (or other modules which are also types of class modules) and not a BAS module.
The primary distinction between Public and Friend is that Public potentially exposes the procedure to other code that's potentially outside of your project. Typically, you are compiling your code to a DLL (and not an EXE) to take advantage of this, but the distinction is maintained either way. And, the Friend declaration limits the exposure of your procedure to the project on which your working.
So, to say again, if in a class, Public may be seen by other programs outside of your project, and Friend is only seen by your project.
Now, when you use Friend, you get some other advantages as well. The primary one is that your project's UDTs can be passed into class procedures declared as Friend whereas they can't be passed into Public procedures (in a class) unless you go through some TypeLib hoops.
That's it in a nutshell, and I'll leave it there.
EDIT1: hahaha, wow, we all jumped on this one. Two posts while I was typing.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Also, just a rule of thumb, if you're in a class module (or form, or user control, or property page), use Friend unless you have a very specific reason to use Public. That's sometimes a bit hard to remember because you have to use Public in BAS modules, but code in BAS modules are never directly exposed to other outside programs. In an ideal world, we might want Private-vs-Friend in a BAS module, but we live with what we've got. So:
In BAS module: Private or Public
In any class module: Private or Friend (unless you have a specific reason to declare it as Public).
----------
Also, just as an FYI, there is one other reason I know of for declaring a procedure as Public (other than exposing it directly to another program). Occasionally, I will be doing some subclassing, or maybe have some callback procedure in some BAS module. Anytime those subclassing procedures or callback procedures call into the procedure of some class module (typically in a form module), I always make sure and declare those class module procedures as Public. I've found that things don't always work correctly if I don't do this.
And, from a certain perspective, in that outlined case, it is another program calling into my program. That is, it's Windows calling into my program.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
An example of where Friend can't be used:
Form1.frm:
Code:
Option Explicit
'This must be Public, not Friend, because we pass ourself to Class1.OtherMethod As Object.
Public Sub Method()
MsgBox "Form1.Method"
End Sub
Private Sub Form_Load()
With New Class1
.OtherMethod Me
End With
End Sub
Class1.cls:
Code:
Option Explicit
Public Sub OtherMethod(ByVal O As Object)
O.Method
End Sub
With changes this works:
Form1.frm:
Code:
Option Explicit
Friend Sub Method()
MsgBox "Form1.Method"
End Sub
Private Sub Form_Load()
With New Class1
.OtherMethod Me
End With
End Sub
Class1.cls:
Code:
Option Explicit
Public Sub OtherMethod(ByVal O As Form1)
O.Method
End Sub
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
So Dil,
Your take home message is that late bound objects can't find methods declared as Friend either.
EDIT1: As, it's virtually certain that they're using the same techniques to find procedures that an external program would use.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
I'm interested because I noticed (especially for Function and Sub) that FRIEND makes the compiled program faster.
There are some benchmarks in that linked thread that shows how much faster Friend is.
Originally Posted by reexre
I have noticed that in some cases FRIEND can raise errors (even if is used only in 1 project).
But I still don't understand why (the cases where) it happens.
Can you elaborate on exactly which error(s) are raised?
Originally Posted by reexre
... maybe with the addition of functioning and non-functioning examples.
... I always make sure and declare those class module procedures as Public. I've found that things don't always work correctly if I don't do this.
Maybe it's because you're not declaring your object variable with the exact Object type required? As the demo here shows, there's no problem with using the Friend scope for callbacks.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Originally Posted by Elroy
So Dil,
Your take home message is that late bound objects can't find methods declared as Friend either.
EDIT1: As, it's virtually certain that they're using the same techniques to find procedures that an external program would use.
Another way of saying that is: Friend methods cannot be called when its class is accessed via Object, i.e.,
Dim o As Object: Set o = myClass. MsgBox o.FriendMethod will fail
Dim c As myClass: Set c = new myClass: Msgbox c.FriendMethod will succeed
Insomnia is just a byproduct of, "It can't be done"
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
The VB6 manual was pretty explicit about this Friend caveat:
Originally Posted by MSDN
Important Because Friend members aren't part of an object's public interface, they can't be accessed late bound — that is, through variables declared As Object. To use Friend members, you must declare variables with early binding — that is, As classname.
Originally Posted by MSDN
Important In order to invoke Friend methods and properties, you must use strongly typed object variables. In the example above, the Widgets collection must use a variable declared As Widget in order to access the SetParent method or the Property Set Parent. You cannot invoke Friend methods from variables declared As Object.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Originally Posted by Victor Bravo VI
Maybe it's because you're not declaring your object variable with the exact Object type required? As the demo here shows, there's no problem with using the Friend scope for callbacks.
Victor, I suspect you are spot-on. In fact, here's a piece of subclassing code (the subclassing procedure) where I do precisely that. In fact, I even have a comment about Public. Also, we must appreciate that the VB.Form class still results in a late bound object.
Code:
Private Function ToDetectMoves_Proc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
If uMsg = WM_DESTROY Then
UnSubclassSomeWindow hWnd, AddressOf_ToDetectMoves_Proc, uIdSubclass
ToDetectMoves_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
Exit Function
End If
If IdeStopButtonClicked Then ' Protect the IDE. Don't execute any specific stuff if we're stopping. We may run into COM objects or other variables that no longer exist.
ToDetectMoves_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
Exit Function
End If
'
Const WM_WINDOWPOSCHANGED As Long = 71&
Dim frm As VB.Form
'
If uMsg = WM_WINDOWPOSCHANGED Then
On Error Resume Next
Set frm = FormObjectFromPtr(dwRefData)
frm.Form_Moved ' MUST be Public (not Friend) to find it from here.
On Error GoTo 0
End If
'
ToDetectMoves_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
End Function
EDIT1: It also dawns on me that the late binding issue is probably precisely where reexre is occasionally seeing a problem.
Last edited by Elroy; Nov 10th, 2019 at 06:03 PM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Originally Posted by Elroy
Also, we must appreciate that the VB.Form class still results in a late bound object.
Yeah, VB.Form is not strongly typed enough. It should be the exact name of your Form (e.g. Form1 vs Form).
BTW, I think you won't need the FormObjectFromPtr helper function if you rewrite the code this way:
Code:
Private Function ToDetectMoves_Proc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, _
ByVal uIdSubclass As Long, ByVal dwRefData As VB.Form1) As Long
Const WM_WINDOWPOSCHANGED As Long = 71&
If uMsg = WM_DESTROY Then
UnSubclassSomeWindow hWnd, AddressOf_ToDetectMoves_Proc, uIdSubclass
ElseIf Not IdeStopButtonClicked Then ' Protect the IDE. Don't execute any specific stuff if we're stopping. We may run into COM objects or other variables that no longer exist.
Select Case uMsg
Case WM_WINDOWPOSCHANGED
dwRefData.Form_Moved ' <-- Can be Friend if declared with exact Object type
End Select
End If
ToDetectMoves_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
End Function
VB6 should automatically cast the dwRefData parameter into the desired Object type if you declare it with that Object type. Of course, the object pointer you pass to that parameter must be a pointer to said object, or else crash.
Last edited by Victor Bravo VI; Nov 10th, 2019 at 06:35 PM.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
wow, thank you very much to all !
my main problem was highlighted by LaVolpe and Elroy
Originally Posted by LaVolpe
Another way of saying that is: Friend can not be called when its class is accessed via Object, i.e.,
Dim or As Object: Set o = myClass. MsgBox o.FriendMethod will fail
Dim c As myClass: Set c = new myClass: Msgbox c.FriendMethod will succeed
Originally Posted by Elroy
It also dawns on me that the late binding issue is probably precisely where reexre is occasionally seeing a problem.
I will carefull read Victor Bravo VI links and other stuff later to learn more,,,
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Hmmm, the declaration of dwRefData as a class is an interesting tip. It's a bit spooky to tamper with the types of a subclassing procedure, but that seems reasonable.
Regarding the strong typing, I keep all of my subclassing routines as general purpose as possible, many times repeatedly using them. So, that part wouldn't work. But, declaring as Public isn't a problem.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Originally Posted by Elroy
It's a bit spooky to tamper with the types of a subclassing procedure, but that seems reasonable.
The data type of parameters doesn't really matter to the subclass procedure as long as they are of the expected parameter size (1, 2, 4 or more Bytes). Data type is an abstraction that the computer doesn't really care about. All it knows is the size (in bytes) of the data you're passing. So, if a callback procedure has provision for a pointer-size argument, you can make use of that to pass a pointer to an object and have VB6 automatically cast it for you. You can even pass a pointer to any data type and have VB6 cast it automatically. For example:
Code:
Option Explicit 'In a Standard (.BAS) Module
Private Type UDT
Member() As Byte
End Type
Private Declare Function CallWindowProcW Lib "user32.dll" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (ByRef ArrayVar() As Any) As Long
Private Sub Main()
Dim B() As Byte, U As UDT
B = App.Path
U.Member = App.Title
CallWindowProcW AddressOf Proc, VarPtr(CurDir$), VarPtrArray(B), VarPtr(U), VarPtr(New Collection)
End Sub
Private Function Proc(ByRef Arg1 As String, ByRef Arg2() As Byte, ByRef Arg3 As UDT, ByRef Arg4 As Collection) As Long
Debug.Print """"; Arg1; """"
Debug.Print """"; CStr(Arg2); """"
Debug.Print """"; CStr(Arg3.Member); """"
Debug.Print Arg4.Count
End Function
Originally Posted by Elroy
Regarding the strong typing, I keep all of my subclassing routines as general purpose as possible, many times repeatedly using them. So, that part wouldn't work. But, declaring as Public isn't a problem.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
As a general question, if I am only using my public function in my own project(that compiles to native exe) , could I just substitute all 'Public Function' to 'Friend Function' in all forms and classes and see a performance improvement in my app?
and maybe do the same replacement for 'public property' to 'friend property'?
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
@axisdj,
As discussed above, the only problem you're going to run into is when you use a late-bound object to try and call some of those Friend procedures. Besides that, yes, what you say should be correct.
If I did that though, I'd be sure and test all the code. A primary problem is that late-bound objects don't check for the existence of their members until they're actually executed (i.e., runtime error), not when compiled. So, good alpha-testing would be warranted if you did that.
-------------
@Victor,
Truth be told, I use my FormObjectFromPtr procedure in several subclassing routines, and some of them have been in the field for years without any problems. And, for stuff that's not clearly mangled, I have a philosophy of, "if it's not broke, don't fix it". The new ideas you outlined are useful, and I'll remember them. But I won't be changing any of my code. Take care.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Minimal performance improvement aside from tight loops, and then inline code might make more sense without paradigm-breaking hacks like Friend for non-Friends. You can also move those things into static modules.
Most people facing performance problems should look for performance-sapping bugs and poor algorithm choices first, after that run a profiler to find specific choke points to micro-optimize.
We've already listed a number of cases above where Friend doesn't work.
It is also meant to be a contract a programmer makes with others who follow. By lying about this contract you make extra work when the time comes to move a class out into a separate Project (DLL, etc.). Every instance of "Friend" must be examined to determine whether it is a real or a lie.
Here's another way to look at it: If you are worried about performance consider how much worse off you'd be if you were using a scripting language like C# or Python.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Originally Posted by dilettante
Minimal performance improvement aside from tight loops, and then inline code might make more sense without paradigm-breaking hacks like Friend for non-Friends. You can also move those things into static modules.
Most people facing performance problems should look for performance-sapping bugs and poor algorithm choices first, after that run a profiler to find specific choke points to micro-optimize.
We've already listed a number of cases above where Friend doesn't work.
It is also meant to be a contract a programmer makes with others who follow. By lying about this contract you make extra work when the time comes to move a class out into a separate Project (DLL, etc.). Every instance of "Friend" must be examined to determine whether it is a real or a lie.
Here's another way to look at it: If you are worried about performance consider how much worse off you'd be if you were using a scripting language like C# or Python.
Yes, I have optimized my code and really do not have a performance issue at all. But running more optimized appeals to me because it could mean I could run more efficiently on micro pc's with very low specs, or even running on an supler low cost ARM via emulation.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Originally Posted by Elroy
If I did that though, I'd be sure and test all the code. A primary problem is that late-bound objects don't check for the existence of their members until they're actually executed (i.e., runtime error), not when compiled. So, good alpha-testing would be warranted if you did that.
in fact, this can be a problem, especially when using a massive replace (... replace all) in a large project. (with a lot of classes).
Using Friend, I have noticed a considerable gain in speed (especially where some Sub or Function are called very frequently within cycles).
So, thinking aloud, I was wondering if it could be a good idea to edit modules, turning them into classes and use the FRIEND statement in their Functions and Subs.
Just a thought ... would it worth it?
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
So, thinking aloud, I was wondering if it could be a good idea to edit modules, turning them into classes and use the FRIEND statement in their Functions and Subs.
I'd be interested in any benchmarks that compare speed of the exact same method in a bas module to that in a class, as Friend. Such comparisons must be made in a compiled application. In the IDE, there is overhead applied to methods in bas modules that do not exist when compiled.
One of the reasons why I feel any speed increase should favor bas modules is that class methods require an extra parameter be placed on the stack & removed whenever a COM method is called. So, based on these assumptions, w/o benchmarks, I'd say the answer to your question is no
Last edited by LaVolpe; Nov 11th, 2019 at 03:20 PM.
Insomnia is just a byproduct of, "It can't be done"
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
I'd be more interested in a benchmark comparing calls to a Public in a class module as opposed to calls to a Friend in a class module.
And yeah, I'd guess that calls to a Public in a BAS module are about as fast as it gets. From my understanding, there's no lookup of any kind there.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Ahhh, well there you go:
Originally Posted by Bonnie West
It appears there's one more difference between Friend and Public procedures: Friend procedures are invoked much faster than the equivalent Public procedure.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Originally Posted by reexre
I have noticed that in some cases FRIEND can raise errors (even if is used only in 1 project).
But I still don't understand why (the cases where) it happens.
As others have already pointed out, this issue is when you attempt to access a Friend method late bound.
I happened to me many times mainly when I tried to get an object using a Friend property of an UserControl from a PropertyPage. It didn't work and raised an error.
In the past, the solution that I used was to make the method Public instead of Friend and to set it as non visible (from the procedures' property window).
Until... I realized of a better way...
To set the not strongly typed variable SelectedControls(0) into a strongly typed one.
Examples attached. Attempt to load the property page to see the problem and solution.
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
wow
~ 8 times faster !
I'm beginning thinking that is some cases it would worth to not use bas modules.
(even though not simple to make a benchmark comparison from "Public in a Module" and "Friend in a Class")
Re: PUBLIC / FRIEND Property (Function Sub) ... Differences ?
Originally Posted by reexre
wow
~ 8 times faster !
I'm beginning thinking that is some cases it would worth to not use bas modules.
(even though not simple to make a benchmark comparison from "Public in a Module" and "Friend in a Class")
Reexre,
The Public in a BAS module is VERY different from the Public in a class module. When a Public is used in a class module, all the software infrastructure to build a public interface is put into place ... and none of that is done for a Public procedure in a BAS module.
As LaVolpe pondered (and I tend to agree), calling a Public procedure in a BAS module is probably the fastest and most direct way for code to call other code.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.