How external methods can make your code platform specific

In Xojo if you use external methods to simplify writing a declare over & the they can make your code platform specific.

How ?

In a method you can wrap the declare in a #if Target so it wont be used on targets its not intended for.

There is NO way to do this for external methods.

So as soon as you use them your code now has a hard dependency on what ever OS api you just exposed. And there is NO way to easily exclude it from being referred to when compiling for other targets. You simply rely in the code using them being excluded by the compiler since its not referenced (you hope)

IF the code using the external method isnt properly wrapped in a #if Target then you can get errors that are hard to track down since the declare wont be right where the error is saying it is. You just get a warning about a library not found.

I ran into this with code called WinAPILibrary

I‘ve forked this library and REMOVED these so anyone can compile the code regardless of the target but it will only function on Windows

The other issue I’ve run into is sometimes you need the same method defined several times because it can take different parameters. This is a bit easier to do, and IMHO, more obvious with several declares where you need thins than maybe several external methods with varying configurations.

My 2 cents FWIW

Antlr 4

Having once upon a time having had to use Lex & Yacc, and their eventual successors Flex & Bison, I’d been more than passingly familiar with writing and debugging grammars.

And all their weirdness like shift reduce conflicts 😛

At Xojo I’d looked through the grammar for the language to make sure various editors and parsers were conforming to the grammar especially in places like the method signature editor where you could paste in the whole thing into the method name and it would pull it apart. There were other places where the grammar had to be known to try & do the right thing.

And when a side project came up that required writing a grammar I knew I was capable of writing one using those tools; but really didnt want to use them as they have some weirdnesses and they only turned out C++ code, maybe Java too. But if you wanted some other language that wasnt an option.

Enter ANTLR !

One of the things I really like about it is not only can you read the grammar very easily, it has some handy test modes like showing you a visual parse tree, dumping all the tokens, a tree of all the tokens and piles of other nice debug info to help you write a better grammar and therefor a better parser.

For instance, originally I had a rule for reading a Xojo DIM statement. And it was much like

// Declare any number of variables/arrays of varying types.
dimStatement
    : (DIM | VAR) (arrayDecl | IDENTIFIER | ME) (',' (arrayDecl | IDENTIFIER | ME))* AS NEW? fqName('(' arguments ')')? (EQUALS expr)?
      (',' ((arrayDecl | IDENTIFIER | ME) (',' (arrayDecl | IDENTIFIER | ME))* AS NEW? fqName ('(' arguments ')')? ) (EQUALS expr)? )* comment? #DeclareVariables
    ;

quite a beast to read but it permitted any sort of single line dim statement to be parsed

HOWEVER, it had real issues when it came to trying to deal with it in code. Why ? well in antler the code would have lists of possible arraydecl objects, identifier objects, fqnames for the type and none of them were easily associated with each other. So it makes it hard to know what arrays were defined as what type, what identifiers were defined as what types & so on.

What do I mean by that ? Given code like

dim k() , I as integer, s() as string, b, bb() as boolean

I’d get

array decls : k, s, b
identifiers : I, b
fqnames : integer, string, boolean

Very hard to tell which array and indents are integers, which are strings and which are booleans

Now this looks like

// Declare any number of variables/arrays of varying types.
dimStatement
    : (DIM | VAR) declClause ( ',' declClause)* comment? 
    ;

declClause :
	(arrayDecl | simplevarDecl ) (',' (arrayDecl | simplevarDecl))* AS NEW? fqName('(' arguments ')')? (EQUALS expr)?
	;

arrayDecl
    : simplevarDecl '(' ( MINUS? number (',' MINUS? number)* )? ')'
    ;

simplevarDecl 
	: (IDENTIFIER | ME) ;

And parsing that same code I now get and array of decl clauses like

decl clause
     array decls : k
     identifiers : I
     fqname : integer
decl clause
     array decls :
     identifiers : s
     fqname : string
decl clause
     array decls : bb
     identifiers : b
     fqname : boolean

and this is much easier to sort out and way easier to handle in code

As I work more on this project I’ll have to keep an eye out for these sorts of things

Antlr makes some of this super easy to deal with

Now I need to find other books on designing grammars for ANTLR 4 to see what else I might be missing out on

How I spent last weekend

Recently I visited a client in Germany
And we worked hard for the 2 weeks I was there

But while I was there I took advantage of the fact I’d be there over a weekend and went to Austria to ski at an enormous resort that had not yet closed – Ischgl.

Driving there I had feelings of dread as all the lower parts of hills like Garmisch-Partenkirchen were closed and obviously very green – but there was snow high up.

So I kept on driving – it was about 2.5 hours from where I was in Germany to Ischgl

As I finally got to the town I saw a LOT of green and my hopes sort of sunk

But again there was snow high up and there were lots of people putting on ski boots & heading across to the gondola. So I got on my gear and headed the same way the crowd was heading.

And am I glad I did. I quickly rented gear and got a ticket and headed up the gondola

Take note – that board isnt listing all the runs that are open. The upper left is all the lifts that are open. There are 42 lifts up there and most were open. The gondola I took up is marked A on that map and there are 2 others that start right in the town itself.


And if you look closely you can see there are several mountains ridges & areas that are possible to ski. Most are labelled – B, M, N, C, L and E

B is the area that the gondola I took initially places you at. And this area is about the same size as the village area of Sunshine village. So I quickly hopped on a chair and rode it up to take a quick spin down.

For the entire day I tried quite hard to not ride the same lift more than once. Although sometimes I had no choice. And I skied and skied and skied. I finally grabbed some lunch from an amazing cafeteria – VERY nice chefs on staff and excellent food ! It was such a nice day I decided to sit on the deck & scope out where I would head for the afternoon (yes thats a lift way off in the distance on that ridge)

I skied and skied and I dont think I got to even half of the lifts before I finally called it a day.

And, after skiing all day, I drove the 2.5 hours back to Germany

Truly had an amazing memorable day

Nice week

Last week Trish & I went to Cancun
We’d planned this sometime ago and we had a really nice week

Visited Isla Mujeres, Chichen Itzá, and went snorkelling a couple times

On the ride over to Isla Mujeres we sat near this gent from Goa India who was on board without his girlfriend (she was sick that day)
We struck up a conversation and it turns out he’s in the same line of work I am
And we had a great visit for about 2 hours
I’m sure Trish was bored as heck as we talked nothing but tech & geek topics the entire time

And when we finally departed the boat we both made a deliberate & concerted effort to find the other & thanked each other for what turned out to be a great conversation which made the trip even nicer

It made nice day even nicer to meet someone as passionate about the things we talked about

And then the last evening we were there we sat with another resident of the condominium and her daughter.

At first the daughter wasnt very engaged in any of the conversations. Then her mom asked about what the heck was going on in Tennessee and the Tennessee three & I explained what that was and what had occurred.

Her daughter then joined in and became quite animated and engaged and we sat & talked politics for a couple hours. She was extremely well spoken and knowledgeable.

And her mom just sat and you could see her smiling as we talked.

And we covered a lot of topics from politics to health care to Canada’s governmental systems and a lot in between.

Eventually it grew late and the young lady departed

At that point her mom leaned over to me and said “Thank you VERY much for finding my daughter in there”

She said that her daughter had, through covid, become quite withdrawn and disengaged and that this was perhaps the most conversation she had engaged in in the last 3 years. Mom was almost in tears as she said her daughter had come out of the shell she built up through covid & all the lockdowns and isolation.

I have to admit that I felt really glad to have “helped” but it was so easy. I just talked to her daughter and we had a great chat. It was thoroughly enjoyable especially to see an under 20 person so knowledgeable and engaged in politics and so much else going on in the USA.

Oh yeah. Cancun was fun too !

Water + Horse ≠ Horse drinking water

The saying is of course “You can lead a horse to water but you cannot are it drink”

And that applies in many contexts
You can show a person a solution to a problem but they’ll still refuse it – for whatever reason they have.

Sometimes the real saying that should be applied is “You can only help someone if they want help”

Again, despite seeming to ask for it, when they get an offer of help that isnt EXACTLY what they wanted they’ll refuse the help.

Then what do you do bug shrug and say “I tried”

Byref and ByVal part II

Long ago I wrote about byref & byval
Apparently this wasnt widely read not even by some long standing members of the community as I still see completely wrong explanations of bevel & byref persist.

First you have to understand that there are two types of VARIABLES.
VALUE types and REFERENCE types.
With a VALUE type the compiler sees there is space in memory set aside when your program runs to hold a value – a number a floating point value etc. The thing IN that spot IS the actual data.
With a REFERENCE type whats in that spot isnt the data directly – it s the address of the data.

Normally when you pass a value you pass it BYVAL
This is the default

So what exactly does this mean ?

I literally means that the value that is held by whatever type of variable is passed in can’t be altered.
If you pass in an integer, IN the method you can change it however you want, but those changes WILL NOT be preserved in the calling code.

Something like

Sub Opening
  dim I as integer = 100

  system.debuglog str(i) // prints 100

  foo(i)

  system.debuglog str(i) // prints 100
end sub

sub foo ( I as integer )
  I = 500
  system.debuglog "in foo " + str(i) // prints in foo 500
end sub

Would print 100 and 500 as indicated. The value would not be preserved from the call to foo. So when we return the next time I is printed in the caller it prints 100.

This is the easy case for a VALUE type.

If we switch to a REFERENCE type its EXACTLY THE SAME ! The trick is “the value” that is preserved is the pointer, or reference, that is preserved. NOT THE data referred to. Let me illustrate

Sub Opening
  Dim d As New date
  System.debuglog d.SQLDateTime
  foo(d)
  System.debuglog d.SQLDateTime

End Sub

sub foo ( d as date )
  
  d = New date(d.year - 2, d.month - 4, d.day - 6, _
    d.hour - 8, d.minute - 10)

  System.debuglog "in foo = " + d.SQLDateTime
end sub

Note that if you run this you will see that d in the main calling routine before & after the call prints the SAME date. This despite the fact that in the called routine, foo, we altered the date that d referred to.
What this shows is that what is being passed by VALUE is the REFERENCE (pointer or address)

And again IN the routine we called we can do whatever we want to change what the REFERENCE is by creating a new one and that change wont stick when we leave.

  • there IS a thing that many people referen to as “byref” that ISNT
    SEE THE END OF THIS ARTICLE

No wit we switch to using BYREF to make it so “changes to the value held” are preserved we get

Sub Opening
  dim I as integer = 100

  system.debuglog str(i) // prints 100

  foo(i)

  system.debuglog str(i) // prints 500 !!!!!!!!!!!!
end sub

sub foo ( byref I as integer )
  I = 500
  system.debuglog "in foo " + str(i) // prints in foo 500
end sub

The change to the value held IS preserved !
BYREF allows us to alter what the variable held

And for BYREF with a reference type its much the same

Sub Opening
  Dim d As New date
  System.debuglog d.SQLDateTime
  foo(d)
  System.debuglog d.SQLDateTime // prints THE SAME as from foo !!!!

End Sub

sub foo ( byref d as date )
  
  d = New date(d.year - 2, d.month - 4, d.day - 6, _
    d.hour - 8, d.minute - 10)

  System.debuglog "in foo = " + d.SQLDateTime
end sub

BYREF lets you change what the VALUE of the passed in variable is.
But, it depends on what kind of value is passed in to see what the effects are

SOME people incorrectly refer to the following as “byref”

Sub Opening
  Dim d As New date
  System.debuglog d.SQLDateTime
  foo(d)
  System.debuglog d.SQLDateTime // prints THE SAME as from foo !!!!

End Sub

sub foo ( d as date )
  
  d.hour = d.hour - 12

  System.debuglog "in foo = " + d.SQLDateTime
end sub

Bu this is NOT “byref”
We haven’t change the REFERENCE ( the actual instance) being referred to

We HAVE altered one of the properties of the item passed in – that happens to be a reference type

I hope this clears up the confusion

Silent code breaking changes :(

Was helping a fellow Xojo user to try & sort out why updating to a new version of Xojo broke their code.

The code still compiled fine. But it just didnt work as expected any longer.

And it turns out that in some classes Xojo changed a get/set pair of methods, which can be overloaded by a subclass, into actual computed properties, that cant be.

They had subclassed the Xojo class and overloaded the method pair to do some custom things. And now, since properties are NOT virtual, all their customizations no longer work.

The trouble with this change is that it IS a silent behavioural change.
And it has the effect I wrote about some time ago – Virtual dispatch for properties

Worst of all there appears to be NO release note or change notice that this was done in the 2022r3.2 release cycle.

Here’s a tiny example of the issue

For starters this is the entire code in a console apps RUN method

Dim c As Class1MethodPair

c = New CustomClass1MethodPair

// given our current set up where Storage is a METHOD this will return the SUBCLASS value 

System.debuglog c.Storage


Dim cp As Class1AsProp

cp = New CustomClass1AsProp

// and now ?????????

System.debuglog cp.Storage

The ONLY difference between these sets of classes is the first implements STORAGE as a get/set pair of methods, which the cubclass CAN properly overload.

And the second Storage is a computed property.

The results wont be what you expect by looking at the code !

The change xojo made is exactly the same, changes behaviour silently, and appears to be undocumented

Fixing code by not touching it follow up

In the case I described the code is in a subclass a Xojo class

The idea here is to INSERT a new subclass between the existing subclass and the new one. And the newly inserted subclass will expose things in a way the OLD existing code wont break

So we never touch the old code
We just modify the inheritance chain in a way we can then alter how things behave

So in his case we can add a new subclass of EmailMessage that exposes the Source as a Method pair ( get & set) and then make the existing class inherit from our new class

And the existing code will then JUST work without ever having had to alter any of it

Next time you have an issue like this consider that as an option !