-
May 14th, 2018, 10:07 AM
#41
Re: GOSUB - Is it really bad?
I'm sure there are times when it may make sense to use a gosub though I am not sure there is ever truly a need for it. I suspect that the only reason it is there is for backward compatibility. In older forms of Basic I used them extensively and was quite happy when I started using a version that did not need them.
-
May 14th, 2018, 10:12 AM
#42
Re: GOSUB - Is it really bad?
I'm sure it's just there for backwards compatibility, as it is never essential. Even the folks who use it say that it makes more sense to them, or seems more reasonable for one case, or is more efficient for a specific case. So, if it were eliminated, code could still be written, the problem could still be solved, it would just be solved in a different fashion.
My usual boring signature: Nothing
-
May 14th, 2018, 10:22 AM
#43
Lively Member
Re: GOSUB - Is it really bad?
Originally Posted by Elroy
However, Tubus, when you say, "In the end, it boils down to: you cannot really hide complexity, you can only shift it around to different places", I suspect you may have a battle on your hands with that one.
... well, sometimes yes, you have a point with this one
-
May 15th, 2018, 06:02 AM
#44
Re: GOSUB - Is it really bad?
Originally Posted by tubus
In the end, it boils down to: you cannot really hide complexity, you can only shift it around to different places.
Yes, and there is some misunderstanding what *is* complexity actually.
From human point of view a long function is complex, a god-like class is complex and you reduce complexity by dividing functions/classes to become more manageable chunks. This usually requires writing more lines of code, which is counter-intuitive -- write more code, for something to become less complex.
"When a solution is too complex, then you usually need *more* classes"
-- Paulo Coelho
cheers,
</wqw>
p.s. Trusting quotes on the internet. . .
-
May 15th, 2018, 06:57 AM
#45
Re: GOSUB - Is it really bad?
@wqweto: That's a good point. For the coding I need to do, I frequently write very long procedures. IMHO, there's always some degree of judgment as to when I need to make another procedure. And, to some degree, it's a matter of personal taste. It's one of those things that's not terribly easy to nail down.
As an example of how it can be a matter of personal taste, I've recently taken a project by The Trick (whom I consider to be, without question, one of the most brilliant programmers on these forums) and reworked it for my own purposes. Here's a certain procedure I started with:
Code:
Public Sub InitializeScene( _
ByVal hwnd As Long)
InitDevice hwnd
InitLight
InitCamera
InitGrid
InitSelectionBox
InitTransformGizmo
mlBackColor = RGB(&H30, &H3F, &H3F) ' // R B are swapped
End Sub
Each one of those Init... procedures was called only once. I'm just learning Dx9, and I found myself jumping around a lot trying to get my head around all those concepts. Therefore, with some additions for my own purposes, my incarnation of that same procedure looks like the following:
Code:
Friend Sub InitializeScene(ByVal hWnd As Long, Optional lBackBufferWidth As Long = 1920&, _
Optional lBackBufferHeight As Long = 1080&, _
Optional lBackColor As Long = &H0&)
' This gets everything needed for Direct3D up and running.
' There are several pre-determined and initial settings made below.
'
Dim uPP As D3DPRESENT_PARAMETERS
Dim uLight As D3DLIGHT9
'
' Some initial settings.
mhWnd = hWnd
mlBackBufferWidth = lBackBufferWidth ' This is the TOTAL width of the BackBuffer, and not just the Viewport setting.
mlBackBufferHeight = lBackBufferHeight ' This is the TOTAL height of the BackBuffer, and not just the Viewport setting.
mlBackColor = lBackColor ' BackColor of the entire scene.
muInitialCameraPos = DxVec(-6!, 4!, -6!) ' Initial camera position. -6, 6, 4 in lab coordinates.
'
' Initialize our mesh collection. This ONLY contains things that will move with the grid.
' The grid and the camera's target mesh are NOT included.
Set mcollMeshs = New Collection
'
' Get Direct3D up and running.
Set moD3Dx = Direct3DCreate9()
'
' Initialize Direct3D device.
With uPP
.BackBufferCount = 1
.Windowed = 1
.SwapEffect = D3DSWAPEFFECT_DISCARD ' After swapping (.Present), discard old BackBuffers. Discard is fastest.
.EnableAutoDepthStencil = 1
.AutoDepthStencilFormat = D3DFMT_D16
'
.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE ' This is necessary to keep the .Present method from slowing things down.
'
.BackBufferCount = 1
.BackBufferFormat = D3DFMT_A8R8G8B8 ' D3DFMT_X8R8G8B8, Let's use alpha (and not X).
'
.BackBufferWidth = mlBackBufferWidth ' This needs to be the maximum of the ScaleWidth of mhWnd.
.BackBufferHeight = mlBackBufferHeight ' This needs to be the maximum of the ScaleHeight of mhWnd.
End With
Set moD3Device = moD3Dx.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mhWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, uPP)
'
' Enable Z_buffer (depth buffer).
' A Z-Buffer, also known as a depth buffer, is simply a large buffer that keeps track of the distance
' from the camera of every pixel on the screen. Whenever a pixel is drawn, it takes the closest pixel to the camera and
' draws that on the back buffer. At the same time, it stores the depth value into the same spot in the z-buffer,
' so that the next time something is drawn, Direct3D can see how close each pixel is, and which objects should be drawn and which should not.
' For more, see: https://msdn.microsoft.com/en-us/library/windows/desktop/bb219616(v=vs.85).aspx
moD3Device.SetRenderState D3DRS_ZENABLE, D3DZB_TRUE ' This just turns it on.
'
' Now we can set the BackBuffer's used area (i.e., the internal ViewPort). It may change if user resizes the hWnd.
SetViewportSize
'
' And now for some lighting.
With uLight
.Type = D3DLIGHT_POINT
.Position = DxVec(0!, 50!, 0!)
.Attenuation0 = 1!
.Range = 100000!
.Diffuse = DxColorWhite
.Specular = DxColor(0.05!, 0.05!, 0.05!)
.Ambient = DxColor(0.8!, 0.8!, 0.8!)
End With
With moD3Device
.SetLight 0&, uLight
.LightEnable 0&, 1& ' Arguments: Light index (we could have multiple), Enabled.
.SetRenderState D3DRS_LIGHTING, 1 ' This turns on lighting. TRUE to enable Direct3D lighting, or FALSE to disable it.
End With
'
' Get the grid going.
Set moGridMesh = New clsDxMesh
With moGridMesh
.CreateGrid moD3Device, 8&
.Position = DxVecZero
.DiffuseColor = vbWhite
.Name = "TheWorldGrid"
End With
'
' A mesh that represents the camera target.
' The camera object really doesn't care about this mesh.
Set moCameraTargetMesh = New clsDxMesh
With moCameraTargetMesh
'.Position = DxVecFromLabXYZ(0, 1, 0) ' Just for testing, it's always set when the scene is rendered.
.CreateSphere moD3Device, 32&, 0.1! ' Just a nice sphere in case we wish to show it.
.DiffuseColor = &HFF8080
.AmbientColor = &HFF8080
.Name = "TheCameraTarget"
End With
'
' Three meshes that show the lab's orientation.
Set moLabXMesh = New clsDxMesh: Set moLabYMesh = New clsDxMesh: Set moLabZMesh = New clsDxMesh
With moLabXMesh
.CreateRod moD3Device, 32&, 0.25!, 0.01!
.Orientation = DxQuatFromLabEulerXYZ(0!, nPI / 2!, 0!)
.DiffuseColor = vbRed
.AmbientColor = vbRed
.Name = "TheLabAxisX"
End With
With moLabYMesh
.CreateRod moD3Device, 32&, 0.25!, 0.01!
.Orientation = DxQuatFromLabEulerXYZ(-nPI / 2!, 0!, 0!)
.DiffuseColor = vbGreen
.AmbientColor = vbGreen
.Name = "TheLabAxisY"
End With
With moLabZMesh
.CreateRod moD3Device, 32&, 0.25!, 0.01!
.DiffuseColor = vbBlue
.AmbientColor = vbBlue
.Name = "TheLabAxisZ"
End With
'
' Get the camera up and running, and set initial position/properties.
Set moCamera = New clsDxCamera
moCamera.Fov = nPI / 4!
'
' ( keep X=Z for 45°)
' camera position target up direction
moCamera.LookAt muInitialCameraPos, DxVecZero, DxVec(0!, 1!, 0!)
End Sub
All of those original calls are gone, and just strung together, with comments, into one much longer procedure. (They're also a bit rearranged, but that doesn't really change anything.) It just helped me to learn this stuff to see the code just drop down through it all.
I think this is one case where Tubus is correct. To paraphrase him, "we can sometimes move complexity around, but we're not necessarily making it simpler."
And, for the other side of the coin, let me return to that form code for my spine protocol. As stated earlier, that thing has about 70 non-event procedures in it. It's chocked full of stuff like ...
Code:
Private Sub LoadSrs30(udt As Srs30ScoresType, rs As DAO.Recordset)
' The rs must be open and sitting on the record before this is called.
' Used by both the encounter and the comparison.
'
udt.bFound = True
udt.FunctionMean = DoubleVal(rs![FunctionMean])
udt.PainMean = DoubleVal(rs![PainMean])
udt.SelfImageMean = DoubleVal(rs![SelfImageMean])
udt.MentalMean = DoubleVal(rs![MentalMean])
udt.SubtotalMean = DoubleVal(rs![SubtotalMean])
udt.SatisfactionMean = DoubleVal(rs![SatisfactionMean])
udt.TotalMean = DoubleVal(rs![TotalMean])
End Sub
... which is called from two other procedures. Or ...
Code:
Private Function bVectorHasData(v As VectorType) As Boolean
bVectorHasData = (v.X <> 0) Or (v.Y <> 0) Or (v.Z <> 0)
End Function
... which is called all over the place. Or ...
Code:
Private Function ButterTheAngles(C3dPoint() As C3dPointFrameDataType)
Dim Buf() As Double
Dim i As Long
'
ReDim Buf(LBound(C3dPoint) To UBound(C3dPoint))
'
For i = LBound(C3dPoint) To UBound(C3dPoint)
Buf(i) = CDbl(C3dPoint(i).X)
Next i
oButter.Filter Buf()
For i = LBound(C3dPoint) To UBound(C3dPoint)
C3dPoint(i).X = CSng(Buf(i))
Next i
'
For i = LBound(C3dPoint) To UBound(C3dPoint)
Buf(i) = CDbl(C3dPoint(i).Y)
Next i
oButter.Filter Buf()
For i = LBound(C3dPoint) To UBound(C3dPoint)
C3dPoint(i).Y = CSng(Buf(i))
Next i
'
For i = LBound(C3dPoint) To UBound(C3dPoint)
Buf(i) = CDbl(C3dPoint(i).Z)
Next i
oButter.Filter Buf()
For i = LBound(C3dPoint) To UBound(C3dPoint)
C3dPoint(i).Z = CSng(Buf(i))
Next i
'
End Function
... which is also called multiple times.
To try and write any of those in-line, rather than make separate procedures, to my eyes, would clearly be making things more complex. In fact, that ButterTheAngles (a Butterworth low pass filter) procedure could possibly be further simplified by overlaying those C3DPoint UDTs with a 2D array, making XYZ an array. But array overlaying introduces a certain complexity in itself, so I doubt I'll be reworking it.
So, it's clearly a matter of taste, to some degree. However, I sometimes just listen to my gut. When it's getting nervous, I start thinking that it's telling me to take a step back and "simplify" this thing, breaking it up into smaller, more manageable pieces. And then, other times, if I'm clicking along with some procedure, putting in appropriate comments, I think it's all fine, with no need to break up anything.
Best Regards,
Elroy
EDIT1: Actually, after staring at that Butterworth procedure, I probably do need to work on that some more. All my C3dPoint data is Single precision, but my Butterworth filter expects Double precision. You can see me jumping through hoops to accommodate that. I should probably write a Single precision Butterworth filter, which wouldn't take that much.
Last edited by Elroy; May 15th, 2018 at 07:05 AM.
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.
-
May 15th, 2018, 07:39 AM
#46
Re: GOSUB - Is it really bad?
Originally Posted by Elroy
To paraphrase him, "we can sometimes move complexity around, but we're not necessarily making it simpler."
That's what I'm trying to debunk. If complexity can only be shuffled then all refactoring efforts are defeated beforehand.
My mantra is: If a system is complex, add more classes! Because it is fairly easy to reduce complexity at the expense of lines of code.
At the same time it is very hard to reduce complexity while reducing lines of code and reducing asymptotic execution time (the Big O notation). You'll need mostly super-star devs to do this.
cheers,
</wqw>
-
May 15th, 2018, 07:57 AM
#47
Re: GOSUB - Is it really bad?
Hi wqweto,
I definitely think we're on the same page.
However, I must say that I've backed off of Class modules to a large degree since it became crystal clear to me that shuttling code into them doesn't reduce the code memory footprint of an executable (unless we take the extra step of actually creating an ActiveX DLL out of those class modules). However, having said that, my primary project certainly has its share of Class modules:
And it's probably going to soon get three more when I weave in my DX9 work (unless I decide to make that an ActiveX or possibly a separate stand-alone program).
IDK, on a large project like mine, managing complexity is a perpetual task, and I'm not sure a one-size-fits-all approach works all that well. I use just about all the tools at my disposal to manage complexity and to keep things organized. And it's not easy.
Best Regards,
Elroy
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.
-
May 15th, 2018, 08:29 AM
#48
Re: GOSUB - Is it really bad?
Personalty, I like GOTO. For Gosub in vb6 haven't used, but if i have to do then there is no reason why not. In my M2000 Interpreter I implement GOTO, GOSUB, ON GOTO, ON GOSUB, with numbers and labels(with : at the end). The reason to use these commands is to get flow control on same scope of variables. Lets skip the use of them in M2000, and see what happen in Vb6.
Visual Basic 6, pass anything by reference or we have to state ByVal otherwise. Why ? Because in final assembly code there is smaller code to use a location in stack frame. This meas that cpu cache has more space for code. So instead of retrieving an address for "same" scope variable, we get it from stack. If we have to use it for less than two or three times then the pushing to stack maybe worse, but it happens to use a variable more than two or three times, so indirect reading, can be faster than direct (less statements in cpu cache, so more "pages" need to be read, in slow speed). A local variable stored to stack, so if we use it in a routine called by a Gosub, we get no new stack frame, and if we are lucky, our code run from cache, so we get maximum performance. But we may have another problem, if we overkill the conditional jumps. Jump prediction in cpu load with a wise way the cache. Gosub and Goto are unconditional "jumps", where a jump here means a change to program counter, or PC in CPU. A call to a function is a Gosub for cpu with some care to stack frame for parameters and local variables. So why in VB code, we get a statement that a Gosub is slower than a function call in compiled code?. The only reason is that in function we have the return value, as a state for our program in specific line of code, that is inside CPU. Using Gosub, we have all state in variables. So the call is the same fast, and maybe faster for Gosub, but we get a penalty for not passing results from cpu registers, but make results in local variables, unless compiler is so good and use registers as local variables.
Look at cpu history for the first 16bit cpu, from Texas. The TMS9900 processor supposed to be the affordable 16bit cpu. This cpu utilize a WorkSpace Pointer register, which is the same idea of using local variables in stack, but for registers. So at the end this cpu luck true registers, and need cycle of read/write memory, and that was a bad idea. When this processor need to push registers, just push the WorlSpace Pointer and get an uninitialized memory for registers, so need to initialize it again. In a multi-thread scenario switching task using just a push of a pointer can be very good. So why Texas sold TI 99/4A sold as a micro without mult-tasking, at least in Basic ? (this was my first computer, not owned, when I learn Basic). In same decade other 8 bit cpu was faster. The famous 6502, was faster from the original 6800, and uses first page (256 bytes) as registers too. And for the finale of this reply, eventually cpu got more registers, then got one level of cache ram, then a second, and then a third, with predictions, speculations, out of order executions, two or more execution pipelines. All this stuff never stand to calling method, but to balance cpu internal to external time for moving bits.
As for the spaghetti code, i have to say that in the other side, the extreme hiding of "under the hood" code is not good. We didn't know exactly what happen in some parameter combinations, or after a series of call in an object, when we don't breakpoint the code inside object. We can do this only at the stages which programmer leave to us. As an example, I make a Text Editor (based on ideas from others here in this forum), and because I made the user control and all of the events, we get a flicker free "note pad". Just check Notepad at resize, to see the flickering. Why Microsoft use this bad "UI control" inside NotePad? This is not a use of spaghetti code, but a use of objects, when object are stay as is, without improvements. "If something is bad but can be sold then is a product to make profit". I expect more from Microsoft. From my stand as programmer, spaghetti code or not, using of Gosub or not, is not a matter of choice, I can use everything to achieve my scope, and this is not so big as those scopes of a big company. What matters is the final work to be useful, to not disturb the user experience, and to give a felt of stability.
-
May 15th, 2018, 09:48 AM
#49
Re: GOSUB - Is it really bad?
Originally Posted by Elroy
However, I must say that I've backed off of Class modules to a large degree since it became crystal clear to me that shuttling code into them doesn't reduce the code memory footprint of an executable . . .
I mean classes in the C++/Java sense of the word i.e. in VB6 terms that would be modules. The idea is to separate *concerns* into different modules.
Anyway, I'm staring here at a 1000+ modules project group at ~800 kLOC but the complexity of the project is not very high IMO. And I'm planing on adding more modules to reduce it further :-))
cheers,
</wqw>
-
May 15th, 2018, 10:14 AM
#50
Re: GOSUB - Is it really bad?
I actually ran into a VB6 limit a couple of years back. I'm not sure if it was Intellisense identifier space or an absolute module limit, but I hit a hard limit. That's when I got truly serious about making ActiveX DLLs a fundamental part of my primary project. It was just an absolute necessity to keep going.
I'm all with you though on keeping complexity down (and organization up). That should be one of the primary goals of a programmer, regardless of their purposes. And it's a skill we should be constantly honing. (Maybe that's why I attempted to strongly suggest to Tubus that he reconsider his use of Goto's.)
Also, I think it's safe to say that accomplishing that simplicity/organization will be different for different projects.
Best Regards,
Elroy
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.
-
May 15th, 2018, 10:19 AM
#51
Hyperactive Member
Re: GOSUB - Is it really bad?
DoEvents() is pure evil. It only has a few legitimate uses but seems to show up everywhere.
-
May 15th, 2018, 10:23 AM
#52
Re: GOSUB - Is it really bad?
I didn't even bring up the misuse of Static.
-
May 15th, 2018, 10:25 AM
#53
Hyperactive Member
Re: GOSUB - Is it really bad?
Originally Posted by dilettante
I didn't even bring up the misuse of Static.
I'd like to hear that rant
-
May 15th, 2018, 10:38 AM
#54
Re: GOSUB - Is it really bad?
Not much to it. Usually what happens is that people use Static and then complain that they can't clear the value back to zero from outside. Or else they don't understand what a Static is and get tripped up because it doesn't get reallocated each call. Or better yet they'll have Static objects and then wonder why their program won't terminate.
If you know what you're doing there is no problem.
-
May 16th, 2018, 09:51 AM
#55
Re: GOSUB - Is it really bad?
"Complexity" is a tough topic and learning to manage it is what separates experts from novices.
Every time you separate functionality into multiple files, you increase complexity. This is as far as the novice gets: they hear "increase complexity" and decide "more files are hard". That's how you end up with an 80,000 line Form1.vb that's impossible to decipher.
The expert understands the goal is to create less complexity than is removed. For very small projects, adopting a very formal Separation of Concerns approach is foolish and you devote more code to infrastructure than work. For very large projects, tools like Design Patterns help us express the things we're doing in ways other experts expect and that decreased cognitive load pays for the extra layers of indirection that are introduced. In a small project, you very rarely end up using extensibility patterns and they are wasted time. In a large project, it's guaranteed you'll need them.
But "complexity" isn't the only tension in software engineering. Sometimes "performance" is the concern. There's a famous, long, heated argument between Linus Torvalds and another developer over the use of a goto within some Linux kernel code. Torvalds (correctly) argued that since this particular bit of code executes millions of times per second and the goto results in fewer cycles per execution, the "loss of clarity" in using the goto is paid for by the millions of cycles saved per second.
So I can't condemn GoSub in any language, but I can ask the developer why it was used. And I think if you see one you should ask why it was used. If there's an answer, and it makes sense, leave it. If there's not an answer, but the code is functioning properly, leave it until you need to change that code. If there's not an answer, but removing it makes the code harder to follow or maintain, leave it.
The worst thing you can do is follow dogma. Don't do things "because the internet says they are bad". Do them because, "I read an article with convincing benchmark evidence that this approach yields impressive performance returns in exactly this scenario."
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
May 17th, 2018, 04:45 AM
#56
Member
Re: GOSUB - Is it really bad?
Originally Posted by wqweto
Yes, and there is some misunderstanding what *is* complexity actually.
From human point of view a long function is complex, a god-like class is complex and you reduce complexity by dividing functions/classes to become more manageable chunks. This usually requires writing more lines of code, which is counter-intuitive -- write more code, for something to become less complex.
"When a solution is too complex, then you usually need *more* classes"
-- Paulo Coelho
cheers,
</wqw>
p.s. Trusting quotes on the internet. . .
This rings very true for me.
I like things to be very simple
A trivial example:
Code:
'I much prefer
dim s as string
s = somefunction(a, b, c)
dim d as integer
d= someotherfunction(s)
dim e as boolean
e = yetsomeotherfunction(d)
'rather than
e = yetsomeotherfunction(someotherfunction(somefunction(a, b, c)))
There's much less thinking involved to understand what's going on.
BTW I know you as wqw on stackoverflow and I've found myself using a lot of your answers from there.
-
May 18th, 2018, 06:19 AM
#57
Member
Re: GOSUB - Is it really bad?
Why all the hate for doEvents or API equiv? If for example you are not at event level and using sockets there is little else to do to get your winsock message actually processed other than wait for your stuff to finish and then have vb return to the main message loop. Remember it is actually pumping messages for you all the time when it is idle with probably PeekMessage, TranslateMessage & DispatchMessage calls.
Mostly what doEvents does anyway I think
-
May 18th, 2018, 06:49 AM
#58
Re: GOSUB - Is it really bad?
Originally Posted by vbcommander
Why all the hate for doEvents
Because all too often it's reached for by those who do not understand the ramifications as a solution to the wrong problem and then don't understand why other things then start to go pear-shaped. That's why.
It's the same thing with gosub, oern, and several other things inherent in BASIC/VB ... there's a few constructs that people latch onto because it was easy and allowed things to "just work" without realizing it was the wrong answer to the problem. And as a result, they get themselves deeper into hot water over it and make things worse.
IF you KNOW what you're doing, IF you UNDERSTAND the implications of what you're doing, AND you're willing to deal with the consequences, AND you understand what is happening and why, then there isn't a problem. It isn't that there's hate for it... it's that there's a healthy dose of pessimistic caution. I think it's safe to say that ideally we'd like to try to avoid those situations when we can, and look for a "better way." But there are times when we can't, but again, it's a near last-resort situation. I haven't written DoEvents, with the exception of in posts here in the forums, in over 20 years... so that just goes to show the "necessity" of DoEvents.
-tg
-
May 18th, 2018, 06:50 AM
#59
Re: GOSUB - Is it really bad?
vbcommander, This is a bit of a bait for you to realize something. But, what's the API equivalent to DoEvents?
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.
-
May 18th, 2018, 07:11 AM
#60
Re: GOSUB - Is it really bad?
Ok, I'll outline the problem with DoEvents. Let's say you're sitting on a form that's something like the following:
Now, there are a few different buttons on that form that make take a few seconds to execute. (Most actually won't, but let's say they will.) I know that the "Copy CSV" and "Export Report" buttons can take a few seconds. Now, let's say that we scatter DoEvents within the code that's under those buttons. What's the harm, right?
On that form above, there's really no need to disable any buttons. In other words, they are all always enabled.
Ok, what does DoEvents do? It's similar to calling a procedure that could possibly be unintentionally recursive. It pauses our code at whatever line it was on, specifically that DoEvents line, and goes and checks the event queue to see if any other events are sitting there waiting to fire. If they are, it fires them. And don't forget, our thread is still paused at our DoEvents line of code. It goes off and runs the code for those other events, and, when done, it returns to our "paused" DoEvents line and then completes our execution (possibly pausing again on the next DoEvents to go off and execute some other event code in our program).
So, with that "Export Report" button, since it takes a few seconds, the user could bounce on that button, recursively executing its code several times before the first time finished. Or, the user could bounce between several buttons, getting code from several sections simultaneously (or somewhat simultaneously, with internal DoEvents lines paused) running.
Hopefully, you can see that this could rather quickly just become a huge mess, causing our program to crash or possibly garble data. At the very least, it makes the code under those buttons exceedingly difficult to debug, with users not being able to accurately tell you what they did before running into some problem.
In other words, in a situation like that form above, when the user executes some code by clicking a button, that code should run to completion before the user is allowed to do anything else. And that's precisely what will happen if there are no DoEvents in the underlying code.
I hope that helps. I think we are all rather universally in agreement on the evils of DoEvents. There's only one very specific example where I use it. And that's where it takes a loop to get some long process done, and you want to give the user the option to "Cancel" before it completes. And, in this situation, you should make sure that a "Cancel" button is the only option available to the user while the long loop is running.
Best Regards,
Elroy
EDIT1: And I'll go ahead and answer my "bait". I assume you're talking about the "Sleep" API call. People get confused but Sleep does something quite different from DoEvents. Personally, I've got no problems with Sleep, if you really feel that you need it for something. All it's going to do is slow down your program.
When you call Sleep, the event queue of your program is not checked. Other waiting events are not allowed to fire. Your program simply pauses at the Sleep statement, returning control to Windows until the Sleep time has expired.
Now let's also realize something else. And this is at a level beyond our program. When we are executing a VB6 program, and let's say we're also in some long running loop. We do not have exclusive control of the CPU. For one, all modern CPUs are multi-core (think multi-thread, but that's not quite right either). However, even if we're on a single-core CPU, a VB6 program still doesn't have complete control of the CPU in a long running loop. Since the beginning of Windows, it's been a true multi-tasking OS. What that means is that it'll "swap out" the CPU's program pointer and give timeslices to other running programs and services, even if our VB6 program is attempting to be a CPU hog. Therefore, unless we specifically need pauses (and I can think of a few good reasons we might), there's typically no need for Sleep either. But again, it doesn't have the deleterious effects that DoEvents has.
EDIT2: Also, DoEvents should never be used as a replacement for refresh. If we need to refresh something, then figure out how to do it with the appropriate .Refresh method. Worst case, figure out how to call an API invalidate call.
Last edited by Elroy; May 18th, 2018 at 07:29 AM.
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.
-
May 18th, 2018, 07:43 AM
#61
Re: GOSUB - Is it really bad?
DoEvents is a bit more nefarious than Elroy indicated because it doesn't just look at the application event queue... in fact, that's not what it even checks... it checks the SYSTEM event queue... so it's looking for messages from EVERYTHING in the system. And that's where the danger begins because the #1 time people use DoEvents is when they are doing something intense that freezes their screen since UI updates are a minor priority... so they use DoEvents to allow UI updates to be processed, not realizing what it's really doing.
-tg
-
May 18th, 2018, 08:15 AM
#62
Re: GOSUB - Is it really bad?
as I wrote before, DoEvents is needed in certain situations, like in a neverending loop but if you create a application that dont use loops in that way, but instead timers, buttons etc, then doevents can mess things up.
and use the API as I also mentioned:
Code:
If GetQueueStatus(QS_ALL) Then DoEvents
Code:
Const QS_KEY = &H1&
Const QS_MOUSEMOVE = &H2&
Const QS_MOUSEBUTTON = &H4&
Const QS_SENDMESSAGE = &H40&
Const QS_POSTMESSAGE = &H8&
Const QS_TIMER = &H10&
Const QS_PAINT = &H20&
Const QS_HOTKEY = &H80&
Const QS_ALL = (QS_MOUSEMOVE Or QS_MOUSEBUTTON Or QS_KEY Or QS_SENDMESSAGE Or QS_PAINT Or QS_TIMER Or QS_POSTMESSAGE Or QS_HOTKEY)
-
May 18th, 2018, 09:16 AM
#63
Re: GOSUB - Is it really bad?
That's what I'm trying to debunk. If complexity can only be shuffled then all refactoring efforts are defeated beforehand.
My mantra is: If a system is complex, add more classes! Because it is fairly easy to reduce complexity at the expense of lines of code.
Those two sentences are in direct conflict with each other. I agree with the second completely but the first is, IMO, wrong.
There is certainly a complexity minimum threshold for any system that no amount of refactoring will get us below. But that doesn't mean we should stop refactoring when that threshold is reached. Instead refactoring becomes about shifting the complexity away from the consumer. When I want a price for my order it's far easier for me to say:-
Code:
Price = myOrder.Price
than it is to say:-
Code:
Price = 0
For Each OrderLine in myOrder.OrderLines
Price = Price + OrderLine.Product.Price * OrderLine.qty
Price = Price - OrderLine.discount
Next OrderLine
Price = Price + 1.125 'Sales Tax
In the first case the complexity is not removed, merely shuffled out of sight.
The best argument against democracy is a five minute conversation with the average voter - Winston Churchill
Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd
-
May 18th, 2018, 09:43 AM
#64
Hyperactive Member
Re: GOSUB - Is it really bad?
Originally Posted by techgnome
so they use DoEvents to allow UI updates to be processed, not realizing what it's really doing.
You are both right about the side effects but this is the main reason why it is evil. Devs around here get one warning about DoEvents.
-
May 18th, 2018, 09:59 AM
#65
Re: GOSUB - Is it really bad?
@FunkyDexter: In your sample refactoring you are not attacking complexity in any way, just shuffling snippets intact. Do you end up with more lines? Not significantly.
Split calulcation into two separate functions: AddRowTotal and ApplyDiscount and now you start dealing w/ complexity. Naming here is obviously very hard and my function names are daft, but you get my point.
cheers,
</wqw>
-
May 18th, 2018, 09:44 PM
#66
Re: GOSUB - Is it really bad?
Originally Posted by DllHell
You are both right about the side effects but this is the main reason why it is evil. Devs around here get one warning about DoEvents.
Maybe it's a matter of semantics, but I disagree... doEvents itself isn't evil... no more than a pentagram is evil, but it's the use of DoEvents that tends to be evil... just like using a pentagram to raise the dead. That's the bad juju.
-tg
-
May 19th, 2018, 01:58 AM
#67
Re: GOSUB - Is it really bad?
Originally Posted by techgnome
Maybe it's a matter of semantics, but I disagree... doEvents itself isn't evil... no more than a pentagram is evil, but it's the use of DoEvents that tends to be evil... just like using a pentagram to raise the dead. That's the bad juju.
Yes, DoEvents in a comment block is pretty harmless for instance. . . lol
cheers,
</wqw>
-
May 19th, 2018, 08:50 AM
#68
Re: GOSUB - Is it really bad?
just because you don't know how to use it, doesnt mean its bad or evil. DoEvents is there for a reason and we need it.
the same with "end", it can be quite evil, but it can be useful and even necessary in some cases (i always use it).
so stop with this nonsense.
-
May 19th, 2018, 09:36 AM
#69
Re: GOSUB - Is it really bad?
Oh wow, End. Now there's one I'll say should never be used for any reason other than possible testing and debugging. I'll go out on a limb and say that it should never be used in production code.
Y'all Take Care,
Elroy
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.
-
May 19th, 2018, 10:59 AM
#70
Re: GOSUB - Is it really bad?
if you "scared" of use it, sure do something else, but that doesnt mean its wrong to use.
i would say that end "should" be used in almost all projects.
of course theres a "termination" procedures, where we stop hooks, unloads, set nothing etc, but at the very end the use of "end" could actually help cleaning the memory if for some unknown reason a API/3rd party Dll didn't unload properly.
sure you can be a pro, knowing exactly what you are doing, unloading your "own" program nicely. but can you be sure that this is the case for all the dll you are using (if any)? or if the OS, or updates changes something and creates a problem when unloading APIs? no "end" for me its quite useful and i want it there, the same with DoEvents.
Last edited by baka; May 19th, 2018 at 11:37 AM.
-
May 21st, 2018, 05:12 AM
#71
Member
Re: GOSUB - Is it really bad?
"Since the beginning of Windows, it's been a true multi-tasking OS. What that means is that it'll "swap out" the CPU's program pointer and give timeslices to other running programs and services, even if our VB6 program is attempting to be a CPU hog"
Actually not quite true or perhaps you are too young to remember. Windows was originally a "cooperative multi-tasking" O/S before I think 3.51 where it was actually required for you to give up the CPU. Proper preemptive scheduling only came later.
-
May 21st, 2018, 05:15 AM
#72
Member
Re: GOSUB - Is it really bad?
Originally Posted by Elroy
vbcommander, This is a bit of a bait for you to realize something. But, what's the API equivalent to DoEvents?
Forgive me if this posts 2wice. It did not seem to work the first time.
I would guess doEvents calls PeekMessage,TranslateMessage and DispatchMessage. It may also call Sleep(0).
And I perhaps mistakenly assumed that everybody knows not to pump messages while already in an event. This leads to madness.
-
May 21st, 2018, 05:21 AM
#73
Member
Re: GOSUB - Is it really bad?
Originally Posted by techgnome
DoEvents is a bit more nefarious than Elroy indicated because it doesn't just look at the application event queue... in fact, that's not what it even checks... it checks the SYSTEM event queue... so it's looking for messages from EVERYTHING in the system. And that's where the danger begins because the #1 time people use DoEvents is when they are doing something intense that freezes their screen since UI updates are a minor priority... so they use DoEvents to allow UI updates to be processed, not realizing what it's really doing.
-tg
Actually I believe it checks the message queue FOR THAT THREAD. Yes it does process everything it finds which is why Mattew Curlands methods of pumping Com synchronization messages is useful for multi threading.
According to his book DoEvents
1) Clears all pending keystrokes from the sendKeys function
2) Clears the thread message queue using PeekMessage and its friends
3) Calls sleep(0) (so it does call this) to give up quantum.
-
May 21st, 2018, 07:05 AM
#74
Re: GOSUB - Is it really bad?
Originally Posted by vbcommander
Actually I believe it checks the message queue FOR THAT THREAD.
How do you PeekMessage for another thread at all?
Btw, Curland's list is not *all* DoEvents does. There is some custom msg handling for keyboard navigation and/or windowless controls (hidden VBFocus) that is out of scope of this discussion.
Curland's msg pump for cross-thread calls is very much obsolete since Windows 2000 when CoWaitForMultipleHandles API was introduced -- it reliably waits for hThread/whatever to get signalled while spinning COM cross-thread messages.
Curland's msg pump for cross-thread calls was not very reliable even before that, I remember non-stop getting ERR_RPC_S_CALLPENDING and family errors while in CoGetInterfaceAndReleaseStream call.
cheers,
</wqw>
-
May 21st, 2018, 07:35 AM
#75
Re: GOSUB - Is it really bad?
@FunkyDexter: In your sample refactoring you are not attacking complexity in any way, just shuffling snippets intact. Do you end up with more lines? Not significantly.
That's exactly my point. In a price calculation with a fixed algorithm you cannot reduce complexity, but that doesn't mean that refactoring is pointless. By "shuffling" (or abstracting) the complexity away into functions, classes etc. you can reduce complexity at the point it's consumed.
Last edited by FunkyDexter; May 21st, 2018 at 07:48 AM.
The best argument against democracy is a five minute conversation with the average voter - Winston Churchill
Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd
-
May 21st, 2018, 07:54 AM
#76
Re: GOSUB - Is it really bad?
Originally Posted by FunkyDexter
you can reduce complexity at the point it's consumed.
That's very significant conclusion IMO
Interfacing has a great part in increasing/reducing complexity, as far as good interfaces' mental models are much easier to comprehend and use.
cheers,
</wqw>
-
May 21st, 2018, 08:04 AM
#77
Re: GOSUB - Is it really bad?
Originally Posted by FunkyDexter
you can reduce complexity at the point it's consumed.
I'll second that motion. It's always a judgment call, and there's sometimes a trade-off between hiding complexity and creating obscurity (but not always, if our functions and arguments are well named and commented).
I must admit that I've followed the rule that "we should push complexity down into the deepest recesses of our code as we possibly can" for many years. This might mean creating general purpose BAS modules, creating general purpose CLS modules, creating spun off ActiveX modules, creating a UDT to keep our data together, or just creating a set of functions that sit at the bottom of some complex FRM module. For any reasonably complex project, there will be levels of how far this complexity is pushed down, depending on the generality or specifics of the actual complexity.
IMHO, the creation of this organization is very close to the definition of reducing complexity.
Y'all Take Care,
Elroy
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.
-
May 21st, 2018, 08:21 AM
#78
Re: GOSUB - Is it really bad?
there's sometimes a trade-off between hiding complexity and creating obscurity
There shouldn't be... but, yeah, there often is. In fact, if you're finding yourself thinking "I wonder how this method calculates the price/drives the car/quacks the duck", that's a pretty strong smell that things aren't as they should be. You should have enough trust to just look at the signature and say "yeah, go and quack my duck for me". But we often have to work with other people's smelly code and it can sometimes be difficult to trust that quacking a duck is all that function's going to do .
we should push complexity down into the deepest recesses of our code as we possibly can
I mostly agree but would like to add a nuance: Complexity should be consumed at the lowest possible level but should be configured at the highest possible. I.e. we should use inversion of control to pass objects down into the darkest recesses of our hierarchy where they can be consumed, but we should decide which classes of objects to pass down right at the top, in a factory, and then pass them down using dependency injection.
The best argument against democracy is a five minute conversation with the average voter - Winston Churchill
Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd
-
May 21st, 2018, 09:11 AM
#79
Re: GOSUB - Is it really bad?
Originally Posted by FunkyDexter
In a price calculation with a fixed algorithm you cannot reduce complexity, but that doesn't mean that refactoring is pointless.
By "shuffling" (or abstracting) the complexity away into functions, classes etc. you can reduce complexity at the point it's consumed.
"Complexity" can be seen in quite a lot of things when developing a solution -
and it is "happening" in quite different areas of any larger project, and those areas are sometimes "opposites"
(meaning, when you decrease complexity in one, you will increase complexity in another).
E.g. - even when we assume that the "DRY"-requirement was met to a certain "sufficient degree",
the structure and organizing of your projects functions still remains "discussable" under different "aspects of complexity", as e.g.:
- deployment complexity and versioning (single Script?, Script with include-dependencies?, single Exe? or Exe with Dll-dependencies?)
- code-organization (Module-breakups, Class-structures, Class-Hierarchy-depth, organization and depth of Helper-Binaries)
- Context- and State-Handling, as well as Argument-passing (also generic Param-Types, or Userdefined-Types - depending on performance)
- Data-placement and Data-Volume (Client only?, Server only?, or "mixed"?, Online/Offline-modes?, Change-frequencies and Caching?)
- maintainability + the extent of Error-Transport and Handling/Logging (Isolation- and Level-depth of your includes or Bin-references?)
- teamsize (single dev, small team, large team)
- used language and/or platform
So there is no real "one size fits all" pattern, which can be applied (depending on the size and kind of your project).
Of course there's a certain "optimum" which can be found (over all aspects listed above) - but only for a given project
which "stands still"... well, most of them don't do you that favour - and therefore refactoring (in one, or all of the above
listed aspects) is a constant companion in real-life-projects.
Olaf
-
May 21st, 2018, 09:21 AM
#80
Re: GOSUB - Is it really bad?
and therefore refactoring ... is a constant companion in real-life-projects
+1 to that
So there is no real "one size fits all" pattern, which can be applied
...and to that.
It chimes with what I was saying about configuring things at the highest (not sure I like the word highest here - "most visible" might be better) possible level. This gives us the best chance of reconfiguring our system's behaviour with a minimum possible impact. Of course, there'll always be some impact but we can aim to keep it to a minimum.
The best argument against democracy is a five minute conversation with the average voter - Winston Churchill
Hadoop actually sounds more like the way they greet each other in Yorkshire - Inferrd
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|