Page 2 of 3
Some thoughts about new X# functionality
Posted: Tue May 04, 2021 3:15 pm
by wriedmann
Hi Dick,
please let me add something to the difference between do case and switch:
when it is possible to use "switch", you should use that because it is faster, less code to type and you have more compile time checks.
But in my own code, I'm able to replace only very few "do case" with "switch" statements, so it largely depends on you own coding style if the "switch" statement has advantages for you.
Wolfgang
Some thoughts about new X# functionality
Posted: Tue May 04, 2021 9:28 pm
by ic2
Hello Wolfgang,
wriedmann wrote:
when it is possible to use "switch", you should use that because it is faster, less code to type and you have more compile time checks.
Technically it's a good advise. But as written above, I prefer the clearer CASE statements where I don't have to lookup elsewhere in the code what I am checking in a Switch statement.
I have to add that almost everything I wrote new in X# is basically done the same way as I would do it in VO. The chance is larger that when I am programming and need a DO..CASE which can also be a Switch that I wouldn't even think that I could use Switch and have started the DO CASE without thinking. Even though I read the WhatsNew and carefully watch the on line sessions and make notes, I hardly have the idea that one of the new language elements is really worth remembering and hence I won't use it. Basically what I explained when I started this subject. I think that unless you directly see an advantage into something not available in VO, or search for something you can't easily realize in the VO way (e.g. in my C# photo program I use a listbox which contains the thumbnail images which I wouldn't know directly how to realize in VO), then it's a kind of routine to solve it the (VO) way one is familiar with.
Nevertheless I will keep your remarks in mind and I think I am going to use a Switch somewhere where I can time the difference.
Dick
Some thoughts about new X# functionality
Posted: Wed May 05, 2021 3:48 am
by wriedmann
Hi Dick,
remembering my "mental" migration from Clipper to VO, first I have worked in VO as I worked in Clipper, adding slowly new VO language constructs.
In my "mental" migration to X# I have done the same thing, and now my code that I write in X# is very different from my VO code as it uses interfaces (really a great thing), collections and local classes, but never arrays as it is written in Core mode. It is a long way the change the mode to think programming, and I'm pretty sure my programming style will evolve also the next years.
There are some constructs I don't use like the "using" statement, but maybe I will adopt them sometimes in the future. For sure, there are some addition to the language where I'm asking myself who may be using them, but maybe there are people liking them, and since the underlying Roslyn platform permits them - why not.
Wolfgang
Some thoughts about new X# functionality
Posted: Wed May 05, 2021 7:33 am
by SHirsch
Hi Wolfgang,
I like the "using" statement very much. The new introduced "USING VAR ..." makes it even easier to use. You don't have to care about disposing the object if it goes out of scope. In normal cases no problem. But what if an exception is thrown. Than you have to write much extra code.
Without using (often seen in sample from the internet an criticized):
Code: Select all
TRY
VAR d := SomeDisposeableClass{}
... some code...
d:Dispose()
CATCH
END TRY
What happens to the native resources if an exception is thrown? Dispose will never be called. Maybe you build a memory leak (depending on the class).
Corrected without 'using' would be:
Code: Select all
LOCAL d AS SomeDisposeableClass
TRY
d := SomeDisposeableClass{}
... some code...
CATCH
FINALLY
d:Dispose()
END TRY
'FINALLY' is always called. So d will always be disposed. But as you see you have to declare d outside the 'TRY' block otherwise it is only visible inside TRY and not in FINALLY.
Better would be (IMHO):
Code: Select all
TRY
USING VAR d := SomeDisposeableClass{}
... some code...
//d:Dispose() //this is called automatically when d goes out of scope, even if an exception is thrown
CATCH
END TRY
So one word more but high impact.
@Robert: please correct me if I am wrong.
Stefan
Some thoughts about new X# functionality
Posted: Wed May 05, 2021 7:59 am
by SHirsch
Hi Dick,
I have to go to the beginning of the statement (which can be very long) to mentally combine nVal and the value in the CASE line.
Not really about switch an case but here my thoughts about your statement:
We have the very same problem in old code. When I have to understand such code to fix some bugs or enhance something. The first thing is refactoring. Extract all code from the CASE to a separated method. Then understand what is does. Give it a describing name. So the CASE is easy to read. Then I often see that half of the code inside the different CASE statements is copy/paste. So next thing is extracting duplicated code to separeted methods. There I often find that in some CASE parts an error was fixed but in the duplicated code it was not. So I fixed some bugs that have never been reported. Or I found code that has never been called.
After digging deeper in the class I see the very DO CASE statement in serveral methods. So next step of refactoring, building a class for each CASE. In VO I create a base class in X# an interface and then inherit from it. What to do then depends on use case. Sometimes the needed class will be constructed in corresponing CASE or it is constructed in Init of the calling class.
Now the code is easy to read and due to the separated class easier to understand and enhanceable for new CASES.
Stefan
Some thoughts about new X# functionality
Posted: Wed May 05, 2021 9:11 am
by ic2
Hello Stefan,
SHirsch wrote:So next step of refactoring, building a class for each CASE. In VO I create a base class in X# an interface and then inherit from it.
It sounds like an interesting project but I find it difficult to imagine how to make a class of a DO CASE and inherit from it and what the advantage is.
Maybe this makes a nice presentation for you if there is ever going to be an X# conference again.
Dick
Some thoughts about new X# functionality
Posted: Wed May 05, 2021 9:30 am
by ic2
Hello Wolfgang,
wriedmann wrote: I have done the same thing, and now my code that I write in X# is very different from my VO code as it uses interfaces (really a great thing), collections and local classes,
To comment on these 3 addition you mention:
Collections: indeed, in VO I would use an array but something like as List is much more readable and easier to understand.
Local classes No idea what it is. Something like nested classes? Or do you mean local functions? I saw these in the presentation but I see no advantage or difference with the regular functions as used in VO.
Interfaces There goes your saving you just achieved with typing a bit less in the Switch statement
. As far as I have seen, interfaces mainly is extra typing of the same code to get some "contract" about what arguments or return types you methods should have. No idea why you need extra code for that. Only advantage I can think of is that you can implement multiple inheritance. I had to use an interface once, when implementing WCF. The web part is C# and the Pc part is X#. These didn't communicate with each other. I created an interface which solved the communication issue but I'd rather would have done without.
Dick
Some thoughts about new X# functionality
Posted: Wed May 05, 2021 9:37 am
by SHirsch
Hi Dick,
just a short sample:
Old code
Code: Select all
METHOD DoStuff1() AS VOID
DO CASE
CASE n == 1
... LARGE CODE PART 1
CASE n == 2
... LARGE CODE PART 2
CASE n == 3
... LARGE CODE PART 3
END CASE
RETURN
METHOD DoStuff2() AS VOID
DO CASE
CASE n == 1
... SOME CODE PART 1
CASE n == 2
... SOME CODE PART 2
CASE n == 3
... SOME CODE PART 3
END CASE
RETURN
METHOD DoStuff3() AS VOID
DO CASE
CASE n == 1
... SMALL CODE PART 1
CASE n == 2
... SMALL CODE PART 2
CASE n == 3
... SMALL CODE PART 3
END CASE
RETURN
The new BaseClass (or Interface):
Code: Select all
CLASS BaseClass
METHOD Large() AS VOID
RETURN
METHOD Some() AS VOID
RETURN
METHOD Small() AS VOID
RETURN
Implementation for the 3 CASES
Code: Select all
CLASS CodePart1 INHERIT BaseClass
METHOD Large() AS VOID
... LARGE CODE PART 1
RETURN
METHOD Some() AS VOID
... SOME CODE PART 1
RETURN
METHOD Small() AS VOID
... SMALL CODE PART 1
RETURN
CLASS CodePart2 INHERIT BaseClass
METHOD Large() AS VOID
... LARGE CODE PART 2
RETURN
METHOD Some() AS VOID
... SOME CODE PART 2
RETURN
METHOD Small() AS VOID
... SMALL CODE PART 2
RETURN
CLASS CodePart3 INHERIT BaseClass
METHOD Large() AS VOID
... LARGE CODE PART 3
RETURN
METHOD Some() AS VOID
... SOME CODE PART 3
RETURN
METHOD Small() AS VOID
... SMALL CODE PART 3
RETURN
And now your the refactored:
Code: Select all
METHOD GetCodeClass(n AS INT) AS BaseClass
LOCAL o AS BaseClass
DO CASE
CASE n == 1
o := CodePart1{}
CASE n == 2
o := CodePart2{]
CASE n == 3
o := CodePart3{}
END CASE
RETURN o
METHOD DoStuff1() AS VOID
LOCAL o AS BaseClass
o := SELF:GetCodeClass()
o:Large()
RETURN
METHOD DoStuff2() AS VOID
LOCAL o AS BaseClass
o := SELF:GetCodeClass()
o:Some()
RETURN
METHOD DoStuff3() AS VOID
LOCAL o AS BaseClass
o := SELF:GetCodeClass()
o:Small()
RETURN
Maybe this gives an impression what I meant.
Now it is easy to add another CLASS without changing DoStuffX methods. Just create the class, enhance GetCodeClass and that's it.
Better readable, debugable, reusable, enhanceable.
I know it is not everywhere possible but in our programs there were quite a few places where this was a very good approach.
Stefan
Some thoughts about new X# functionality
Posted: Wed May 05, 2021 9:45 am
by wriedmann
Hi Stefan,
thank you very much for your comments about the "using" statement.
Initially I don't used the "var" statement because XIDE had no support for it, and since I'm used to clean up my objects also in VO and after an "end try" ("end sequence" in VO code).
But maybe I habe to rethink on this as it would save code (normally I don't declare variables in the middle of a function/method to have more readable code: all variable declarations in the start of the method).
Wolfgang
Some thoughts about new X# functionality
Posted: Wed May 05, 2021 9:53 am
by wriedmann
Hi Dick,
the .NET interface has a very large advantage: you can declare some common methods/properties.
A sample:
I have a processing class that is called both from a Windows service and a WPF application.
To process exceptions, progress messages and so forth, they call a method in the owner.
So I can define an interface:
Code: Select all
interface IProcessingOwner
method Progress( cText as string ) as void
method ProcessException( oEx as Exception, cSuppData as string ) as void
end interface
and use that instead of the real class in my processing class:
Code: Select all
class Processing
protect _oOwner as IProcessungOwner
constructor( oOwner as IProcessingOwner )
return
.....
end class
And both my Windows service and my WPF application can implement this interface and pass themselves to the processing class.
Wolfgang