-
May 13th, 2022, 09:53 AM
#41
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by Shaggy Hiker
You need one other thing: A jump statement. I don't believe that any ASM language can be capable without one. They are the basis of conditionals, loops, and all other flow control.
Jump statements are covered by my more general description of being able to manipulate the program counter. Jump instructions, call and ret instructions and interrupts are covered by this. They all work by changing the program counter. The program counter is just a register that holds the address of the next instruction to be executed by the CPU.
Last edited by Niya; May 13th, 2022 at 09:57 AM.
-
May 13th, 2022, 10:15 AM
#42
Re: [RESOLVED] VB.Variant vs C#.Object
You know when I think about it a little more deeply, it can be broken down a tad bit more. These 3 things are all you need for a fully functional computer:-
- The ability to read from and write to storage.
- The ability to perform boolean algebra on two storage locations and write the result to storage.
- The ability to change the program counter both conditionally and unconditionally.
With those 3 things alone you can create a programming language of any complexity. You can derive a lot from just those 3 things. For example addition and subtraction can be derived from boolean algebra and multiplication and division can be derived from addition and subtraction. If-Then logic can be derived from subtraction and conditional jumping. Loops can be derived from both conditional and unconditional jumping. These things can then be built up towards even more advanced stuff like function calls which can be further be built into method calls on objects. You could just go on and on and on with additional complexity by building one system on top of another.
-
May 13th, 2022, 02:11 PM
#43
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by Niya
Jump statements are covered by my more general description of being able to manipulate the program counter. Jump instructions, call and ret instructions and interrupts are covered by this. They all work by changing the program counter. The program counter is just a register that holds the address of the next instruction to be executed by the CPU.
I thought you might have been covering it that way, but I do feel the jump is more fundamental than the program counter. The program counter is one way to manage sequence, and it's the way most commonly used, but jump is required whether or not program counters are the mechanism used to manage sequence.
Still, it's just a matter of view. If the program counter is used as an abstract concept, then, yeah, it is interchangeable with jump. The underlying concept is that you must have a means to designate the next action taken.
My usual boring signature: Nothing
-
May 13th, 2022, 02:16 PM
#44
Re: [RESOLVED] VB.Variant vs C#.Object
Program counters are pretty fundamental since they are used as the instruction-fetch index. They aren't always simple counters though.
I think it was the IBM 650 that used a magnetic drum as primary store. Every instruction contained the address of the next instruction. The compilers and loader used this to try to decrease the delay between instructions, since drum rotation needed to be accounted for or else you might need to wait for nearly a full rotation to fetch each "next" instruction in sequence.
-
May 13th, 2022, 11:40 PM
#45
Re: VB.Variant vs C#.Object
Originally Posted by Elroy
To my way of thinking, a Variant is an intrinsic type (but I suppose that depends on your definition of "intrinsic type"). It's certainly not an object, other than the fact that it might contain a pointer to an object. A Variant has no vTable nor reference counter nor methods. It's just a 16 byte "thing", with the first two bytes being an integer code that specifies what the remaining 14 bytes are. And the remaining 14 bytes (or a portion thereof) are the actual data (or a pointer to the data in the case of strings, arrays, and objects).
In other words, there's nothing fancy about Variants. They're just, occasionally very useful, 16 byte "flexible" variables. In my experience, they're quite fast. Compared to an explicitly typed variable, they just have the minor overhead of looking up their "type" and then applying all the typical rules for using that "type" (which any/all variables have).
Also, you'd be shocked at how many of the input arguments to the VB6 language's functions are actually Variants. If we just started out with Variants, we'd save all that type conversion (to Variant) when calling all the VB6 functions. (But I'm definitely not recommending that.)
I believe Elroy knows this but for anyone who doesn't; there's Variant versions and explicitly typed versions for many of these, like Left, or Mid. They're distinguished by the variable type symbol.... If you use Left(string, #), that's expecting a Variant and will do a type conversion to a Variant and then potentially back. But if you use Left$(string, #), that's explicitly typed for a String, and no type conversion is performed. You can see this in the Object Browser, where 2 different functions are listed:
Function Left(String, Length As Long)
Function Left$(String As String, Length As Long) As String
Function ChrW(CharCode As Long)
Function ChrW$(CharCode As Long) As String
Function LCase(String)
Function LCase$(String As String) As String
-
May 14th, 2022, 07:06 AM
#46
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by Shaggy Hiker
I thought you might have been covering it that way, but I do feel the jump is more fundamental than the program counter. The program counter is one way to manage sequence, and it's the way most commonly used, but jump is required whether or not program counters are the mechanism used to manage sequence.
Still, it's just a matter of view. If the program counter is used as an abstract concept, then, yeah, it is interchangeable with jump. The underlying concept is that you must have a means to designate the next action taken.
Well when you think about it, a jump is defined in terms of the program counter. A statement like jump to address 0x56fcab10 is exactly the same as saying set the program counter to 0x56fcab10.
-
May 14th, 2022, 08:50 AM
#47
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by fafalone
I believe Elroy knows this but for anyone who doesn't; there's Variant versions and explicitly typed versions for many of these, like Left, or Mid. They're distinguished by the variable type symbol.... If you use Left(string, #), that's expecting a Variant and will do a type conversion to a Variant and then potentially back. But if you use Left$(string, #), that's explicitly typed for a String, and no type conversion is performed. You can see this in the Object Browser, where 2 different functions are listed:
Function Left(String, Length As Long)
Function Left$(String As String, Length As Long) As String
Function ChrW(CharCode As Long)
Function ChrW$(CharCode As Long) As String
Function LCase(String)
Function LCase$(String As String) As String
Yes, I was quite aware of those distinctions. However, many VB6 functions just say "number" or "expression" for their input arguments. And, when tested, they work equally well with a variety of input types. It's difficult to say with certainty without some disassembly, but I always assumed that pretty much all of those went in converted to Variants, and then were possibly further validated inside the intrinsic procedure.
ADDED:
Let's take Int() as a trivial example. In its case, it appears to even attempt to preserve the output type (put into a Variant):
Code:
Option Explicit
Private Sub Form_Load()
Dim n As Single
Dim d As Double
n = 123.45
d = 678.91
Debug.Print TypeName(Int(n)) ' Shows "Single"
Debug.Print TypeName(Int(d)) ' Shows "Double"
End Sub
Last edited by Elroy; May 14th, 2022 at 08:55 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 14th, 2022, 09:10 AM
#48
Re: [RESOLVED] VB.Variant vs C#.Object
Int is a function. Fully qualified it's actually VBA.Int. It takes a Variant and returns a Variant. TypeName cannot distinguish between type T and a Variant of type T.
-
May 14th, 2022, 03:53 PM
#49
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by Niya
Int is a function. Fully qualified it's actually VBA.Int.
Btw, this is the biggest lie the compiler makes you believe in. Int is an intrinsic and has nothing to with VBA.Int as its implemented as a direct call to runtime impl (one or several exports of MSVBVM60, one of the __vbaInt exports figuratively speaking). Many languages need such runtime support i.e. multiplying __int64 in C/C++ on a 32-compiler calls into a runtime function.
Shift+F2 (Go to definition) lies and open object browser in VBA.Int but this is a travesty. This is not what get's called *unless* you use VBA.Int i.e. explicitly prefix with lib name.
cheers,
</wqw>
-
May 14th, 2022, 05:07 PM
#50
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by wqweto
Btw, this is the biggest lie the compiler makes you believe in. Int is an intrinsic and has nothing to with VBA.Int as its implemented as a direct call to runtime impl (one or several exports of MSVBVM60, one of the __vbaInt exports figuratively speaking). Many languages need such runtime support i.e. multiplying __int64 in C/C++ on a 32-compiler calls into a runtime function.
Shift+F2 (Go to definition) lies and open object browser in VBA.Int but this is a travesty. This is not what get's called *unless* you use VBA.Int i.e. explicitly prefix with lib name.
cheers,
</wqw>
Wow I did not know this at all.
I can't find anything on __vbaInt through Google. What is it's signature? I'm curious about it's return type and the type of it's parameter.
-
May 15th, 2022, 04:21 AM
#51
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by Niya
I'm curious about it's return type and the type of it's parameter.
This is the point of the compiler "hijacking" certain functions -- it can codegen more optimal implementation based on parameters/expected result data-types so no Variant conversion happens at all.
This code
Code:
Private Sub Form_Click()
Dim l As Long
Dim n As Single
Dim d As Double
l = 456
n = 123.45
d = 678.91
Print Int(l)
Print Int(n)
Print Int(d)
End Sub
. . .compiles to this
Code:
Private Sub Form_Click()
00401914 55 push ebp
00401915 8B EC mov ebp,esp
00401917 83 EC 0C sub esp,0Ch
0040191A 68 C6 10 40 00 push offset ___vbaExceptHandler (4010C6h)
0040191F 64 A1 00 00 00 00 mov eax,dword ptr fs:[00000000h]
00401925 50 push eax
00401926 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
0040192D 6A 18 push 18h
0040192F 58 pop eax
00401930 E8 8B F7 FF FF call VB@TEXT (4010C0h)
00401935 53 push ebx
00401936 56 push esi
00401937 57 push edi
00401938 89 65 F4 mov dword ptr [ebp-0Ch],esp
0040193B C7 45 F8 B0 10 40 00 mov dword ptr [ebp-8],offset __real@4@4005f6e6660000000000+8 (4010B0h)
00401942 8B 45 08 mov eax,dword ptr [Me]
00401945 83 E0 01 and eax,1
00401948 89 45 FC mov dword ptr [ebp-4],eax
0040194B 8B 45 08 mov eax,dword ptr [Me]
0040194E 24 FE and al,0FEh
00401950 89 45 08 mov dword ptr [Me],eax
00401953 8B 45 08 mov eax,dword ptr [Me]
00401956 8B 00 mov eax,dword ptr [eax]
00401958 FF 75 08 push dword ptr [Me]
0040195B FF 50 04 call dword ptr [eax+4]
Dim l As Long
Dim n As Single
Dim d As Double
l = 456
0040195E C7 45 E8 C8 01 00 00 mov dword ptr [l],1C8h
n = 123.45
00401965 D9 05 A8 10 40 00 fld dword ptr [__real@4@4005f6e6660000000000 (4010A8h)]
0040196B D9 5D E4 fstp dword ptr [n]
d = 678.91
0040196E DD 05 A0 10 40 00 fld qword ptr [__real@8@4008a9ba3d70a3d70800 (4010A0h)]
00401974 DD 5D DC fstp qword ptr [d]
Print Int(l)
00401977 FF 75 E8 push dword ptr [l]
0040197A FF 75 08 push dword ptr [Me]
0040197D 68 10 16 40 00 push offset ___vba@07C6D058 (401610h)
00401982 E8 CF F7 FF FF call ___vbaPrintObj (401156h)
00401987 83 C4 0C add esp,0Ch
Print Int(n)
0040198A D9 45 E4 fld dword ptr [n]
0040198D E8 BE F7 FF FF call @__vbaFPInt (401150h)
00401992 51 push ecx
00401993 D9 1C 24 fstp dword ptr [esp]
00401996 FF 75 08 push dword ptr [Me]
00401999 68 18 16 40 00 push offset ___vba@07C6D064 (401618h)
0040199E E8 B3 F7 FF FF call ___vbaPrintObj (401156h)
004019A3 83 C4 0C add esp,0Ch
Print Int(d)
004019A6 DD 45 DC fld qword ptr [d]
004019A9 E8 A2 F7 FF FF call @__vbaFPInt (401150h)
004019AE 51 push ecx
004019AF 51 push ecx
004019B0 DD 1C 24 fstp qword ptr [esp]
004019B3 FF 75 08 push dword ptr [Me]
004019B6 68 20 16 40 00 push offset ___vba@07C6D070 (401620h)
004019BB E8 96 F7 FF FF call ___vbaPrintObj (401156h)
004019C0 83 C4 10 add esp,10h
End Sub
004019C3 C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L25:
004019CA 8B 45 08 mov eax,dword ptr [Me]
004019CD 8B 00 mov eax,dword ptr [eax]
004019CF FF 75 08 push dword ptr [Me]
004019D2 FF 50 08 call dword ptr [eax+8]
004019D5 8B 45 FC mov eax,dword ptr [ebp-4]
004019D8 8B 4D EC mov ecx,dword ptr [ebp-14h]
004019DB 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
004019E2 5F pop edi
004019E3 5E pop esi
004019E4 5B pop ebx
004019E5 C9 leave
004019E6 C2 04 00 ret 4
So Int of Long is a noop (completely removed from codegen) and Int of Single/Double uses __vbaFPInt
cheers,
</wqw>
-
May 15th, 2022, 05:26 AM
#52
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by wqweto
This is the point of the compiler "hijacking" certain functions -- it can codegen more optimal implementation based on parameters/expected result data-types so no Variant conversion happens at all.
Ah. I see now. It seems that these runtime functions are specifically optimized to be embedded by the compiler. I could not help but notice this:-
Code:
; Print Int(n)
fld dword ptr [n]
call @__vbaFPInt (401150h)
push ecx
fstp dword ptr [esp]
__vbaFPInt doesn't even use a normal calling convention. The above code implies that it reads the floating point number directly from the x87 FPU stack, performs the conversion and places it right back on the FPU stack. Because it doesn't have the extra baggage that comes with normal calling conventions it would be much faster than calling a "real" function. It makes perfect sense.
Do you know if CInt, CLng, CStr etc also work this way?
-
May 15th, 2022, 08:06 AM
#53
Re: [RESOLVED] VB.Variant vs C#.Object
Originally Posted by Niya
Do you know if CInt, CLng, CStr etc also work this way?
I'm positive they do.
There are subtle differences with intrinsics though e.g. you cannot do CLng(AddressOf MyProc) while VBA.CLng(AddressOf MyProc) compiles fine.
Btw, in "normal" calling convention FP params/retval are on the FPU stack so __vbaFPInt must be callable from C/C++ just fine.
cheers,
</wqw>
-
Dec 7th, 2022, 04:55 AM
#54
Thread Starter
Frenzied Member
Re: VB.Variant vs C#.Object
Originally Posted by Niya
It would still work because even when not dealing with the Object type directly, we can be sure that whatever type we pass into a generic parameter will have a ToString method because it is implemented on Object which all types inherit from without exception. This is even more important when it comes to hash table implementations. You can pass an object of any type into a hash table because the hash table can be sure that whatever is passed in will have a GetHashCode method.
This is just one reason why the .Net Object type could be considered superior to Variants in VB6.
When I searched for information, I saw the reply above again, so I wanted to leave a mark to make it easier to search information in the future.
Lately I've been learning about C#'s generic and serialization features, and I seem to have a new understanding of VB.Variant and C#.Object. The generics and serialization of C# bring great convenience to programming, but it makes the language very complex and bloated. I'll compare whether other languages have a better solution for dealing with generics and serialization. Until there is a better solution, VB.Variant seems like a good compromise.
Last edited by SearchingDataOnly; Dec 7th, 2022 at 05:04 AM.
-
Dec 7th, 2022, 07:49 AM
#55
Re: VB.Variant vs C#.Object
Originally Posted by SearchingDataOnly
When I searched for information, I saw the reply above again, so I wanted to leave a mark to make it easier to search information in the future.
Lately I've been learning about C#'s generic and serialization features, and I seem to have a new understanding of VB.Variant and C#.Object. The generics and serialization of C# bring great convenience to programming, but it makes the language very complex and bloated. I'll compare whether other languages have a better solution for dealing with generics and serialization. Until there is a better solution, VB.Variant seems like a good compromise.
Just being petty here but Serialisation is more of a framework / runtime feature not a language feature - there is nothing specific to C# relating to serialisation.
Generics on the other hand I would say aren't really adding bloat or even making the language that complex, they add a nice type-safe way of dealing with things without the complexity of something l;ike C++ templates or involving runtime checks and overheads.
-
Dec 8th, 2022, 02:45 AM
#56
Thread Starter
Frenzied Member
Re: VB.Variant vs C#.Object
Originally Posted by PlausiblyDamp
Just being petty here but Serialisation is more of a framework / runtime feature not a language feature - there is nothing specific to C# relating to serialisation.
Generics on the other hand I would say aren't really adding bloat or even making the language that complex, they add a nice type-safe way of dealing with things without the complexity of something l;ike C++ templates or involving runtime checks and overheads.
Serialization requires the type of Object, and C#'s type system (including reflection) is quite complex.
Serialization and C#'s complex typing also make C#'s Exception mechanism extremely complex, and in the dotnet framework, there are nearly 400 system-classes related to Exceptions.
IMO, Generic has a 20% advantage over VB.Variant, but adds 80% more complexity.
In addition, all data types in C# are inherited from object, that is, all data types are objects. I don't know if this is a trend in modern programming languages. I've always felt that data types of programming language should still be divided int basic(primitive) and complex (object) data types.
Last edited by SearchingDataOnly; Dec 8th, 2022 at 06:55 AM.
-
Dec 8th, 2022, 02:02 PM
#57
Re: VB.Variant vs C#.Object
Originally Posted by SearchingDataOnly
Serialization requires the type of Object, and C#'s type system (including reflection) is quite complex.
Serialisation is more of a framework feature than a language thing and it certainly requires reflection. C#'s type system (and the .Net type system in general) is not the same as reflection. You could certainly have C# types without reflection ever being used or needed. Reflection is a way to look at types at runtime, it requires the type system but it isn't part of the type system.
Originally Posted by SearchingDataOnly
Serialization and C#'s complex typing also make C#'s Exception mechanism extremely complex, and in the dotnet framework, there are nearly 400 system-classes related to Exceptions.
Although Exceptions are serializable that is more to do with marshalling them between AppDomains rather than intrinsically something to do with Exceptions themselves. Also saying it is complex because there are 400 exception types is like saying VB6 is complex because there are 400 error numbers. The exception mechanism isn't that complex, it is just inherited classes, the inheritance hierarchy may be complicated at times but that doesn't mean the underlying mechanism is complex.
Originally Posted by SearchingDataOnly
IMO, Generic has a 20% advantage over VB.Variant, but adds 80% more complexity.
Those seem completely arbitrary numbers but I am not going to argue percentages, however if you want / need type safety then generics give you that at the compiler level and Variant doesn't.
Originally Posted by SearchingDataOnly
In addition, all data types in C# are inherited from object, that is, all data types are objects. I don't know if this is a trend in modern programming languages. I've always felt that data types of programming language should still be divided int basic(primitive) and complex (object) data types.
Technically the "all data types inherit from object" claim often used is a lie, it is a convincing enough and convenient lie but it is a lie. See https://learn.microsoft.com/en-us/ar...es-from-object for a bit more detail on that topic.
The problem with primitive / complex types being separate is you get into the Java situation of having an int (primitive) and an Integer (object) duplication (along with other similar types). In dotnet the compiler handles the difference between them, in code you treat everything as an object but the compiler treats things like integers as primitives.
-
Dec 8th, 2022, 02:05 PM
#58
Re: VB.Variant vs C#.Object
Originally Posted by SearchingDataOnly
In addition, all data types in C# are inherited from object, that is, all data types are objects. I don't know if this is a trend in modern programming languages. I've always felt that data types of programming language should still be divided int basic(primitive) and complex (object) data types.
Some languages do that ... in Java there's 'string' which is a primitive, and 'String' which is the object which inherits 'string' .... the difference is that string.Trim() won't work but String.Trim() would ... a better example would be long and Long ... Long as a .ToString() method while long doesn't since it's a primitive.
-tg
-
Dec 11th, 2022, 12:25 AM
#59
Thread Starter
Frenzied Member
Re: VB.Variant vs C#.Object
Originally Posted by PlausiblyDamp
Serialisation is more of a framework feature than a language thing and it certainly requires reflection. C#'s type system (and the .Net type system in general) is not the same as reflection. You could certainly have C# types without reflection ever being used or needed. Reflection is a way to look at types at runtime, it requires the type system but it isn't part of the type system.
Yes, 90-95% of the reasons why C# is powerful is due to the .Net framework (platform), and 5-10% is due to C# itself. This also indirectly shows that C#.Object is not much better than VB.Variant.
Originally Posted by PlausiblyDamp
Although Exceptions are serializable that is more to do with marshalling them between AppDomains rather than intrinsically something to do with Exceptions themselves. Also saying it is complex because there are 400 exception types is like saying VB6 is complex because there are 400 error numbers. The exception mechanism isn't that complex, it is just inherited classes, the inheritance hierarchy may be complicated at times but that doesn't mean the underlying mechanism is complex.
The complexity comparison between C# and VB6 is similar to the comparison between 400 classes and 400 error numbers.
Originally Posted by PlausiblyDamp
Those seem completely arbitrary numbers but I am not going to argue percentages, however if you want / need type safety then generics give you that at the compiler level and Variant doesn't.
IMO, the benefits of C#'s generics also come primarily from the .Net framework, not the C# language itself.
Originally Posted by PlausiblyDamp
Technically the "all data types inherit from object" claim often used is a lie, it is a convincing enough and convenient lie but it is a lie. See https://learn.microsoft.com/en-us/ar...es-from-object for a bit more detail on that topic.
The problem with primitive / complex types being separate is you get into the Java situation of having an int (primitive) and an Integer (object) duplication (along with other similar types). In dotnet the compiler handles the difference between them, in code you treat everything as an object but the compiler treats things like integers as primitives.
It's nice to know this, which also solves another question I had about why C# types all inherit from object but still have high performance (for example, it's often used in game development).
C# has a lot of excellent features, and I still need to learn about it in depth. Thank you, PlausiblyDamp.
-
Dec 11th, 2022, 12:31 AM
#60
Thread Starter
Frenzied Member
Re: VB.Variant vs C#.Object
Originally Posted by techgnome
Some languages do that ... in Java there's 'string' which is a primitive, and 'String' which is the object which inherits 'string' .... the difference is that string.Trim() won't work but String.Trim() would ... a better example would be long and Long ... Long as a .ToString() method while long doesn't since it's a primitive.
-tg
It's a good solution. We can use a similar approach in VB6, for example: Integer and String are primitive types, and IntegerEx and StringEx are encapsulated as objects for primitive types. Thank you, tg.
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
|