# Predict The Output



## Oorang (Feb 12, 2009)

Try to guess the final values of i, j, & k before you run the code.

```
Option Explicit
Sub PredictTheOutput()
    Dim i&, j&, k&
    i = 10: j = i: k = i
    MySub (i)
    MySub j
    MySub k + 20
    MsgBox Join(Array(i, j, k), vbNewLine), vbQuestion, "Did You Get It Right?"
End Sub
Public Sub MySub(ByRef foo As Long)
    foo = 5
End Sub
```
 
I got "i" wrong.


----------



## Patience (Feb 12, 2009)

I didn't quite understand the question at first - but when I thought it through (several times) I realised what I was doing was right. Just that the answers I was getting were wrong. I only got i right.


----------



## TinaP (Feb 12, 2009)

d'oh!


----------



## Stormseed (Feb 12, 2009)

Oorang, 

Could not you think of something else, some fun like your other thread which was Question & Answer type ? It was good fun. 

This one is again the same thing that we all do on Excel Questions board room.


----------



## MorganO (Feb 12, 2009)

Very interesting bit of code!

I've learned a few things I didn't know about how VB works, but still do not understand one piece.  I won't ask directly about it just yet to give others an opportunity to look and guess, but am wondering if you are going to provide a step by step look at how the 'MySub' routine is working on the passed values.

Thanks for the challenge!

Owen


----------



## Oorang (Feb 12, 2009)

Will do, let's give it a litte more time though


----------



## Norie (Feb 12, 2009)

Owen

Why not set up some watchs on variables, sprinkle the code with a few breakpoints and stir with F8?

That should give you some insight on how the code is working.

PS I cheated and ran the code before guessing but I've not voted because I don't understand the poll.

Oorang

Do you work for some government organisation that creates polls just to confuse people?


----------



## ZVI (Feb 12, 2009)

I’ve been cautious  as well as … wrong  at the assumption of 'i' estimation.

Amazed has thought  about the difference on syntax and at last has understood that received result of code was absolutely correct from the point of VBA-parsing rules view 

Nice brick of VBA wall, thank you!


----------



## Richard Schollar (Feb 12, 2009)

I technically only got 1 right (j=5) but my defence is that I wasn't wearing my glasses and thought the assignment lines were:

i=1;j=1;k=1


----------



## Domski (Feb 12, 2009)

Not 42 then?


----------



## Colin Legg (Feb 12, 2009)

I kinda cheated because I've seen the thread that prompted Aaron to start his one, so I had a wee heads-up on it ....


----------



## Greg Truby (Feb 12, 2009)

OK, so anybody got a link to someplace explains why the parenthesis syntax does not pass by reference?  Totally caught me off guard.


----------



## ZVI (Feb 12, 2009)

I could try to explain, or should wait for one more dozen of mistaken?


----------



## Norie (Feb 12, 2009)

I actually didn't think the code would even compile.

But what do I know.


----------



## RoryA (Feb 12, 2009)

There's an MSDN blog here. Usually gets people when they are passing an object.


----------



## ZVI (Feb 12, 2009)

So I'm not the first who has canceled an intrigue, but Rory and MS have made it. Here is my explanation: 

```
<font face=Courier New>
' Could be declared as Sub Y(ByRef X) as well.
Sub Y(X)
  X = 5
End Sub

Sub X()
  
  Dim A As Long, B As Long
  A = 1
  B = 2
      
  ' Reference of A variable is passed, A is changeable by Sub Y()
  Y A
   
  ' Reference of VBA internal run-time variable referenced to result of A+B is passed
  ' Neither A nor B is changeable by Sub Y()
  Y (A + B)
  
  ' Reference of VBA internal run-time variable referenced to result of A+B is passed.
  ' Variable A is not passed therefore it is not changeable by Sub Y()
  Y (A + 7)
  
  ' The same as above with replacing of 7 by 0 (zero)
  ' Reference of VBA internal run-time variable equal to result of A+0 is passed.
  ' Variable A is not changeable by Sub Y because expression into () brackets
  ' means auto creation in memory of VBA temporal internal run-time variable with
  ' reference to value of evaluated expression includes into () brackets.
  ' No special VBA-parsing of expression into the brackets is provided
  ' irrespective of it includes one or more variables or constants.
  Y (A)
   
  ' But Call syntax means passing expression in brackets as reference.
  ' Reference of A variable is passed, A is changeable by Sub Y
  Call Y(A)
  
  ' Reference of VBA internal run-time variable equal to result of A+B is passed.
  ' Neither A nor B is changeable by Sub Y as it not passed
  Call Y(A + B)
  
End Sub
</FONT>
```


----------



## ZVI (Feb 12, 2009)

There is another and easier one, but who knows?

```
<font face=Courier New>
' It could be easy done by [A3]=Day(Date)
' But could you fix .Evaluate("=DAY(" & x & ")") ?
' BTW, I know how it could be fixed :)
Sub WhatIsWrong()
  Dim x
  x = Date
  [A1] = x
  
  With Application
    
    ' Correct
    [A2] = .Evaluate("=DAY(A1)")
    
    ' Wrong
    [A3] = .Evaluate("=DAY(" & [A1] & ")")
    [A4] = .Evaluate("=DAY(" & x & ")")
    Debug.Print .Evaluate("=DAY(" & x & ")")
    
    ' How to fix it?
    [A4] = .Evaluate("=DAY(" & *???* & ")")
    
  End With
  
End Sub
</FONT>
```
Regards,
Vladimir


----------



## Patience (Feb 13, 2009)

I am beginning to think maybe me getting one out of three was more luck than judgement...


----------



## hatman (Feb 13, 2009)

Hmm, I see I wasn't the only one who got the value of "i" wrong.  To be honest, I have gotten in the habit of using the Call statement in these cases (mostly).  The very nature of the Call statement syntax forces the use of parentheses, resulting in the expected output.  I'm not sure WHY I started using Call several years ago... I wonder now if I didn't get annoyed with the "unpredictable" results outlined by Oorang's code.


----------



## Norie (Feb 13, 2009)

hatman

I don't think using Call is a bad idea.

In fact it might be a good idea.

Obviously you can run other subs just simply using there name, dependent on how their located and named/declared.

But people reading the code might be thinking - is it a variable, is it a sub, is it a function, is it an aardvark, can it fly.


----------



## hatman (Feb 13, 2009)

Norie said:


> hatman
> 
> I don't think using Call is a bad idea.
> 
> ...


 
Case in point is ZVI's code... naming a subroutine Y is just evil


----------



## Norie (Feb 13, 2009)

Don't see a problem with Y.

A lot of times when posting quick and dirty code I use t for the sub name when I create a new one.

Obviously I don't include that in what I post, best to use a descripitive sub name - helps organising, identifying etc.

Mind you that pesky aardvark seems to be changing some of my sub names when I asleep.

Perhaps I should put it out before I turn in, but that might be a bit cruel - the crazy cat might find him.

Mind you who would win if they fought, perhaps we should ask Harry Hill.


----------



## ZVI (Feb 13, 2009)

hatman said:


> Case in point is ZVI's code... naming a subroutine Y is just evil
> --------------
> “Homogenized pasteurized milk from confinement animals…”


Whether Y symbol should be considered as a logo of poor confinement animals mentioned in your post Signature?


----------



## ZVI (Feb 13, 2009)

Well, I am sorry for use of evil Y sub name.
Agree that names should be more informative.

This example illustrates that HomogenizedPasteurizedMilk () is made approx. in 1.4 times faster than RawUnpasteurizedMilk() because it's evil method.


```
<font face=Courier New>
Sub PastureFedVsConfinementAnimals()
  Dim t#, evil As Boolean
  t = Timer
  For i = 1 To 10000000
    ' Comment one out of two lines below
    HomogenizedPasteurizedMilk evil
    'RawUnpasteurizedMilk evil
  Next
  t = Timer - t
  MsgBox "Evil=" & evil & " " & Format(t, "0.###") & " sec"
End Sub

Sub HomogenizedPasteurizedMilk(evil As Boolean)
  evil = True
End Sub

Sub RawUnpasteurizedMilk(evil)
  evil = False
End Sub</FONT>
```

BTW refer to my post #17 issue, I don't know why, but
.Evaluate ("=DAY(" & CLng(x) & ")") or setting  format of A1 cell to General/Numeric before .Evaluate("=DAY(" & [A1] & ")") solves issue.

Regards,
Vladimir


----------



## Oorang (Feb 17, 2009)

OK, so here is the explanation:
When you pass a variable "By Value" (ByVal) to a procedure a new spot in memory is created and the value the procedure received is copied into that new spot. So if "foo" is created ByVal it's actually a copy of the variable it was passed. 
If you pass the same variable By Reference (ByRef) the procedure will say OK, the variable is located at XYZ memory address, and while the calling procedure was referring to that address as "j", we are going to refer to it as "foo". If the procedure is altering the same memory address we were calling "j", when we get back up to where that address is referred to as "j" again... Of course the value has changed. So no mystery as to how what happened to "j". But what happened to "i" and "k"?
Well that gets a little more complicated... Let's talk about "k" first. Using a math operator is essentially calling a native function. Think about this imaginary function like this:


```
Sub Example()Code:
    Dim x As Long
    x = 1 + 2       'This
    x = Add(1, 2)   'Is a lot like this.
End Sub
 
Function Add(ByVal value1 As Variant, ByVal value2 As Variant) As Variant
    'Magic
End Function
```
Performing an operation is a lot like a function in that it still has inputs (parameters) and more importantly, output. Now about that output... Have you ever wondered where function's output goes to if you don't load it into a variable? It gets loaded into a temporary spot in memory, and that spot is thrown away when the procedure ends. So when you do "MySub k + 20" you are not passing MySub the address to k, you are passing it the temporary address where the function's output went. So MySub received 30 (the output of k + 20) alters the memory location of the output, but not k itself. So k is never changed. 
So about i... Well turns out, that's just a bug that got turned into a feature. If you want to pass a variable to a ByRef parameter without worrying about your value getting changed, you surround it in parentheses. (I know, not too obscure right?)


----------



## ZVI (Feb 17, 2009)

Oorang said:


> ...
> So about i... Well turns out, that's just a bug that got turned into a feature...


It is feature but not the bug. Compilation always includes the parsing of expression for further calculation. When parser have found parentheses() then expression surrounded by parentheses is expected because it is a rule of parsing. Compiler in this case always creates temporary variable for storing result of evaluated expression even if expression is the single variable. 
The rule is not the bug. The bug is something that contradicts declared rules.
But sometimes the rule can be strange or even erroneous


----------



## Oorang (Feb 17, 2009)

I suppose it's a matter of perspective. To your point, it is in parenthesis, therefore it's a expression. An unforgiving me agrees. On the other hand, a lot of effort went into making VB a forgiving language. So you could make the case that the compiler can/should detect that the expression wasn't actually doing anything. But to be honest, now that I know about it... I like it the way it is. It's nice to know I can prevent a ref parameter from changing my variables if I want too

By the way... Props to everyone for voting so honestly. I expected to see a lot of people claiming 4s


----------



## Oorang (Feb 17, 2009)

Colin_L said:


> I kinda cheated because I've seen the thread that prompted Aaron to start his one, so I had a wee heads-up on it ....


lol I just realized who you were. I feel honored and stuff


----------

