X Platform drawing

@jotter I think you also miss the use of VARIANT as wholly unhelpful

A person could pass in an integer - and the method call would compile and fail spectacularly at run time
Pushing errors out to runtime is probably one of the worst things about this design
The earlier you catch errors the better
Catch them at design time they are easy to fix - no code written yet
Change the design

At compile time - well not perfect but no code has shipped

But at runtime its way too late !

I’m sure I hear the

Oh but just TEST the type at runtime to make sure its a Graphics or WebGraphics !
So now the code is

#If TargetDesktop Or TargetMobile Then
   if (context isa graphics) = false then
       return
    end if
    Var g As Graphics = context
#EndIf
 
#If TargetWeb Then
   if (context isa WebGraphics) = false then
       return
    end if
   Var g As WebGraphics = context
#EndIf

That still leaves the issue as a RUNTIME one
and the CALLER is 100% unaware that their call has failed when passing the wrong parameter type (ICK !)

The compiler cant help you at all (which I personally think is a huge downfall)

An interface would certainly make life a bit easier - at least the graphics & web graphics would present a similar API

Variants subvert the type subsystem in Xojo and should be avoided so the compiler CAN help warn about wrong parameter types, type mismatches etc

Having to resort to them for this code is great example of a bad design leaking into the wild where you have no choice but to deal with that bad choice

4 Likes

Something you MIGHT consider is writing your own wrapper class
So DrawBoard looks like

 DrawBoard(context as MyWrapper)

And calls to it are like

Var cb As New Checkerboard

dim wrapper as new MyWrapper(g) 
cb.DrawBoard( wrapper(g) )
cb.DrawCheckers(wrapper(g) )

MyWrapper then can have one constructor for Web and one for Desktop (thanks to compatibility flags)

the web only constructor

Public Sub Constructor(g as webGraphics)
        instance = g  
End Sub

the desktop only constructor

Public Constructor(g as Graphics)
         instance = g
end

Instance might be a variant property internally (not exposed to the world)

And then the MyWrapper exposes the various drawing methods of whatever it got called with

Sub DrawingColor(assigns c as Color)

   #If TargetDesktop Or TargetMobile Then
     Var g As Graphics = context
   #EndIf
 
   #If TargetWeb Then
     Var g As WebGraphics = context
   #EndIf 
 
   g.drawingColor = c

end sub

function DrawingColor() as color

   #If TargetDesktop Or TargetMobile Then
     Var g As Graphics = context
   #EndIf
 
   #If TargetWeb Then
     Var g As WebGraphics = context
   #EndIf 
 
   return g.DrawingColor
end function

and so on

At least this way YOU can provide some consistency by wrapping it however you want
And the compiler can help you out by flagging erroneous calls and usage

1 Like

For their Example Project it would be enough to just use the Constructors approach (without the overhead of the Wrapper class - you know… they’re marketing for “citizen developer”, not more experienced ones :wink: ).

Class 'Checkerboard':

Public Sub Constructor(g As WebGraphics) // Include in Web only, Public
  context = g
End Sub


Public Sub Constructor(g As Graphics) // Include in Desktop and Mobile, Public
  context = g
End Sub

Private Sub Constructor() // Private, so you can't instantiate without Parameter
  
End Sub

And I’d also change the conditional compilation parts… What if at some time it’s neither TargetDesktop, TargetMobile and also not TargetWeb? Not good enough to just check with #If for a single case.

#If TargetDesktop Or TargetMobile Then
  Var g As Graphics = context
#ElseIf TargetWeb Then
  Var g As WebGraphics = context
#Else
  #Pragma Error "Unsupported Target"
#EndIf 

Oh well… I guess we all have ideas and suggestions how to do better.

All I wanted to point out on TOF is that providing such example projects (and even marketing them via Blog…) doesn’t look good for them :wink:

5 Likes

Variants are so bad in these situations. Feels like typical Xojo ‘solution’ though.

4 Likes

THIS!!!
On the other hand… have you expected something else?
Let’s wait till the first comes around and offers an Addon to sell…

1 Like

I ran into this exact same issue with one of their blog posts, and this was pretty much the same answer, it’s just an example of how it could be done.

new users are going to think

This comes from the CEO. He MUST know what he’s doing

and run with it as if its great code

And this sort of thing sets them on a bad path

1 Like

and don’t forget any AI parsing through their side and learning BS

Personally I feel the approach discussed is bullshit.

It is better to integrate and use Skia for cross platform drawing functions.

maybe a better 2d library but that wasnt the point of the original post

More about how what is shown by Xojo is just a bad example

Using a variant pushes any problems later in the design / build / test cycle which is almost always worse

1 Like

And here I thought you were originally going to point out the inanity of having two differently named objects for the same function in a “X Platform” environment…

Also not exactly related to the original post’s point (which is well taken), but this is where I really have come to appreciate Julia’s multiple dispatch. I’d also note that plotting/graphics libraries these days present a common API but allow you to swap out backends. Seems like maybe that’s what should be happening here if the difference is drawing to a desktop graphics context vs something like a web canvas.

Jurg already did that in his original post on TOF
And the I agree - but then they did the whole rename Buttons as DesktopButton, WebButton, iosButton, MobileButton thereby ruining any shared code possibilities there on much the same basis
Generic code has to use variants and type check at runt time to make sure the code doesnt blow up because you passed an INTEGER not a button :man_shrugging:

2 Likes

Strangely, I seem to spend about zero time on TOF anymore…

These kinds of workarounds (again, due to an unforced error in the first place), and all the rest of the gymnastics with interfaces, etc. (hey, wasn’t inheritance supposed to manage all of that?) has soured me on OOP. Not just Xojo, but I’ve seen similar contortionism in C++ and Python. Julia’s multiple dispatch handles things elegantly, giving you what you mean, and seems eminently more approachable (and certainly more explainable) to “citizen developers.”

1 Like

Indeed THIS is a problem

No - Xojo is like Java here and only supports single inheritance so interfaces are extremely common (multiple inheritance has its own set of problems - looking at you C++)

C++ has bigger issues since it does support multiple inheritance

Leaving things until runtime defers the problems, if any, until later in the cycle and that becomes more costly to fix.
Dunno if the compiler could alert a person to an ambiguous usage but I know dynamic dispatch based on runtime type has been requested before
Right now it uses declared type which has its own set of issues

1 Like

Julia is AOT/JIT compiled, with types inferred or annotated. In some sense, the compiler is there at runtime. There are also tools for helping to achieve what’s referred to a type stability.

Since it isn’t OOP, we’re not dispatching on the (singular) object type, but rather the runtime types of method arguments as a whole.

Which could be considered insulting to the intellect of Xojo’s customers because it’s the opposite direction of most x-platform toolkits.

For example, in SwiftUI which covers Mac, iPad, iPhone, Android*, Watch, TV and Vision Pro, it’s the same code to make a Button, it’s even just called Button.

*to compile for Android requires a 3rd party tool.

2 Likes

But Apple only properly supports it’s own ecosystem, so Swift and SwiftUI are not really x-platform tools. I think, 3rd party Android transpiler is also a bit pricey at 99$/month.

1 Like

But also at codenameone it is one button for Android, iOS, Web and also Desktop. There is no difference and there has no difference to be included. XoJo could implement exactly that also without any problem. It is even for free. Also you could implement with Kotlin Multiplatform or you implement with JavaFX and GluonMobile/Desktop. Many possible ways to do and I think even C# has capabilities to do so. Xojo is not one of them. They have implemented their own ecosystem. Source compatibility is not one of their targets.

1 Like

Well after 12 days Geoff responded to @jotter
:man_facepalming:

1 Like

Geoff Perlman describes the role of citizen developers in Xojo's ecosystem as central and empowering, emphasizing that Xojo is designed to enable individuals who may not be professional developers to create powerful, native applications.

yet many many times he has said the exact opposite, therefore fitting the narrative to the situation at hand

1 Like