Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

toward using C++/WinRT to develop iOS apps as part of “DLL all the things” #330

Closed
optikos opened this issue Feb 15, 2018 · 34 comments
Closed

Comments

@optikos
Copy link

optikos commented Feb 15, 2018

background: Islandwood's/WinObjC's wrapper of Objective-C runtime to .DLL & .winMD

First off, thank you immensely much for bringing C++/WinRT into existence. Although C++/WinRT (and Modern-C++ before that) has done a beautiful job of making standard‡ C++ capable of elegantly writing UWP apps, it seems that C++/WinRT is on the verge of making something equally as miraculous possible: making standard‡‡ C++ capable of elegantly writing native‡‡‡ iOS or MacOS apps (instead of Objective-C or Swift or the Objective-C graft-on within Objective-C++).

‡ instead of C++/CX

‡‡ instead of Objective-C++ and (most notably!) instead of C++/CX, as rajsesh indicated on 27 November 2017.

‡‡‡ For the remainder of this thread, let's define ObjCRT-native (i.e., Objective-C runtime native) as the way that Objective-C and Swift generally present their object files and libraries to iOS and MacOS, ignoring the finer points of Swift runtime differing from (or layer on) Objective-C runtime. If the topic of Xamarin.iOS even arises herein, let's completely ignore the Mono+ObjCRT alternative (extrapolated) definition of “native” that Xamarin.iOS utilizes; herein let's redesignate that Xamarin.iOS flavor of “native” as called Mono+ObjC iOS apps (or if one insists on the word native: Mono-native iOS apps). I somewhat doubt that Xamarin.iOS would even arise again in this thread, because, as apparently effectively indicated by Miguel de Icaza himself on 23 January 2018, Mono lacks the ability to participate in the .winMD world for the foreseeable future; hence the current way that C# and F# (but not C++/CX and Visual Basic) can develop via Xamarin.iOS atop Mono‡‡‡‡ can be ignored along this thread. Hence the reason that I omitted C# and F# from the “instead of” list of languages capable of producing (ObjCRT-)native apps for iOS and MacOS.

‡‡‡‡ instead of preXamarin-Microsoft's .NET proper, ignoring .NET Core overlap of .NET proper with Mono

And now returning to C++/WinRT's 2nd potential miracle, earning it the de facto name C++/RT, taming not only WinRT but also ObjCRT:

It seems as though C++/WinRT is on the verge on making the following sequence of steps possible:

  1. Have an existing Xcode project on a Mac. Also, have the Windows SDK 17025 installed on a Windows 10 computer (e.g., slow-ring Windows 10 Insider Preview of 17025).
  2. Import that Xcode project into VisualStudio 2017 running on Windows 10, as if one were going to author (in Visual Studio 2017 on Windows 10) a garden-variety C++ non-UI library supporting (as backend processing) a UI coded entirely in Swift or Objective-C on Xcode.
  3. Pair Windows 10's Visual Studio 2017 with that Mac to somewhat seamlessly build & (push & pull &) execute that C++ library that is shared between Visual Studio on Windows 10 and Xcode on the Mac.
  4. But instead of behaving ourselves to write merely some backend-processing library, we instead:
    4.1) Copy each iOS (or MacOS for that matter) Objective-C runtime framework {Foundation, UIKit, (AppKit,) ...} over to Windows 10.
    4.2) Invoke Islandwood's/WinObjC's objc2winmd tool to wrap the Objective-C runtime as a WinRT component, producing both .DLL† and .winMD for each Apple framework.
    4.3) Invoke cppwinrt.exe to project the WinRT-componentized iOS (or MacOS) framework into C++/WinRT source.
    4.4) Utilize the generated C++/WinRT-ized projection of each objc2winmd-ized Apple framework in our C++ library that is shared between Visual Studio 2017 on Windows 10 and Xcode on MacOS.
    4.5) Assure that the generated .DLL†† is copied to Xcode to be packaged into the app.
    4.6) From Swift or from Objective-C in Xcode-based source code, invoke at least one entry point in the C++ library that is shared between Xcode on Mac and Visual Studio 2017 on Windows 10. Those invoked C++ member-functions then instantiate UI objects from Apple's Objective-C frameworks via the objc2winmd-ized .DLLs that were copied over.

† Oops, by default on Windows-10-based Visual Studio, this .DLL is likely produced as x86-64 ABI to be consumed on Windows 10—not as an ARM ABI to be consumed on Apple iDevices. But then again WinObjC is open source and Clang/LLVM-based, so it is conceivable to coerce it to produce an ARM ABI for Apple iDevices and to produce an Intel ABI suitable for MacOS. Perhaps this .DLL produced as x86-64 is less of an issue if the app in Xcode is for MacOS, which is Intel-based nowadays (instead of PowerPC).

†† in an ARM ABI for Apple iDevices for iOS apps; in an Intel ABI for MacOS apps

It seems that
a) the lack of some VSIX smoothness
and
b) perhaps the ABI in which the objc2winmd .DLL is generated to target
and
c) copyright/licensing restrictions regarding copying Apple's Objective-C runtime frameworks and .winMD/.DLL derivative-works thereof
are the 3 weakest links in the chain. Where can I learn more (especially from Microsoft itself) about utilizing C++/CX for iOS development in order to then in turn determine the feasibility of C++/WinRT for iOS development?

@devhawk
Copy link

devhawk commented Feb 15, 2018

From https://docs.microsoft.com/en-us/cpp/cppcx/visual-c-language-reference-c-cx

C++/CX is a set of extensions to the C++ language that enable the creation of Windows apps and Windows Runtime components in an idiom that is as close as possible to modern C++.

You can't use C++/CX for iOS development.

@optikos
Copy link
Author

optikos commented Feb 15, 2018

@devhawk, I am expecting a deep reading of my issue above, not a shallow reading. Of course, the party line until now is that C++/CX has been focused on UWP, not iOS. We all know that for multiple years. But it appears that well-memorized old party-line positions might be starting to erode & crumble due to rather recent 2017 releases from Microsoft of open-source tools such as WinObjC and its objc2winmd.

To my point, the 15 September 2017 date on the C++/CX webpage that you provided predates by 2 months the 27 November 2017 date that rajsesh indicated in a reply to WinObjC GitHub issue #20 that WinObjC's objc2winmd would permit C++/CX to access Objective-C runtime's types (presumably as part of porting Objective-C .m/.mm code from iOS to UWP, not the opposite direction that my issue above is driving the topic). WinObjC is Clang/LLVM-based, so presumably it conceivably still retains its ability to target its DLLs/ELFs toward an ARM ABI that is suitable for iOS (and an Intel ABI that is suitable for MacOS), as .app, .so, or .dylib just as Clang normally does for iOS and MacOS. DLL all the things.

@optikos
Copy link
Author

optikos commented Feb 15, 2018

@devhawk, btw, based on some of Kenny Kerr's public comments about your innovative boundary-pushing experimentation with C++/WinRT, you were the one & only person on the planet who I thought might have conceived of all of my issue above ahead of my stating it.

@devhawk
Copy link

devhawk commented Feb 15, 2018

I'm on this thread because Kenny pointed it out to me. :)

@devhawk
Copy link

devhawk commented Feb 15, 2018

I'm pretty sure that clang doesn't support C++/CX. So if you built a WinRT component in ObjC via the objc2winmd tool, you wouldn't be able to access it on iOS from C++/CX.

@optikos
Copy link
Author

optikos commented Feb 16, 2018

@devhawk, let's not fixate on the “C++/CX for iOS” botched clipped-form wording of what I meant: “Where can I learn more (especially from Microsoft itself) about how C++/CX is utilized to port formerly iOS-based source code to UWP as well as any ancillary/tangential capabilities that WinObjC has in addition to that use-case?” As I have said twice before, I am not really interested in using C++/CX for doing iOS development. Any interest in C++/CX that I have herein related to WinObjC is to learn from whatever pieces of the puzzle that they have for the iOS→UWP direction that can be repurposed in the opposite direction for C++/WinRT, using the .winMD and whatever LLVM-based Objective-C-runtime library-building capabilities still exist within WinObjC. Obviously rajsesh's reply and alovchin91's original posting are both implicitly discussing porting an iOS app to UWP. Conversely, the WinObjC and objc2winmd portions of that use-case appear to have at least a latent amount of the Clang/LLVM and iOS-related capabilities to utilize C++/WinRT the other direction‡ (without C++/CX ever entering the conversation at all in the objc2winmd→C++/WinRT→Xcode→iOS[-Xamarin.iOS-esque] direction).

‡ if WinObjC's LLVM backend can still generate the customary LLVM-centric library formats for iOS-suitable ARM ABI and MacOS-suitable x86-64 ABI. If so, then can it generate those Apple-esque libraries in objc2winmd mode instead of WinRT-component .DLL?

I will be opening mirror-image issues over at WinObjC tomorrow.

@devhawk
Copy link

devhawk commented Feb 16, 2018

I was addressing the question of C++/CX because that was the question you asked in the original post. I don't quite understand why you are interested in it. I'm pretty sure it has no role in the WinObjC story beyond "can consume WinRT Components implemented with objc2winmd".

I would think the files generated by cppwinrt would be more interesting for you to look at. In particular, you'll notice in base.h that there are clang specific compiler directives. However, that is clang on windows. While cppwinrt is iso standard c++, there are a variety of windows dependencies which would keep it from working on other platforms.

@optikos
Copy link
Author

optikos commented Feb 16, 2018

@devhawk, I jammed in that final question at the end of the original issue above simply because I had written a substantial issue, but had never asked a question. I jammed in whatever perfunctory open-ended question came to mind—hence why the final question wasn't worded as tightly as the rest of the issue. The focus of the issue is every word other than the last sentence. The final question is there only because it seems odd to post an issue without asking a question or reporting an extant bug. I guess I could have jammed in “Please critique each step above regarding its feasibility, as well as point out additional investigative lines of reasoning to support this use-case.”

I am not expecting everything to work straight from Microsoft today. Yes, I am assuming that there are some Windows dependencies that would need to be edited out from the files generated by cppwinrt.exe. These dependencies would be replaced by Apple-framework dependencies‡ instead, such as via an AST-based Clang source-code transformer.

‡ or better yet: replaced by dependencies on iOS-/MacOS-consumable libraries output by a modified winmd2objc in Islandwood/WinObjC, where those libraries in turn are what depends on Apple frameworks, because the API façade of those libraries mimics the API façade of WinRT-component DLLs. This would keep the DLL-centric architecture of C++/ObjCRT analogous to the DLL-centric architecture of C++/WinRT. DLL all the things.

I am assuming some source-code modification of Islandwood's/WinObjC's winmd2objc and of perhaps objc2winmd too, so that they have command-line options to generate libraries whose ABI is consumable on iOS and on MacOS instead of .DLLs consumable on UWP.

What I am doing is gap analysis to see how many and how big the gaps are, to then determine feasibility.

@devhawk
Copy link

devhawk commented Feb 16, 2018

Sorry, I have a hard time following your writing style with all the footnotes. That's why I simplified and answered the one question you asked.

I'm not 100% clear exactly what you are attempting to do - so it's hard to judge it's feasibility or help you with a gap analysis. I think you want to be able to write an app in standard C++ that you can cross compile for iOS and Windows. On the surface, that sounds pretty infeasible. However, since WinObjC has implemented many Apple frameworks on Windows and has a tool that purports to wrap ObjC frameworks in WinRT, it may be more feasible that it looks on the surface.

It does seem like a lot of effort to go thru if your goal is to write your app in C++ instead of ObjC. Especially since I don't think this approach will work on Android. I'm not aware of any java / winrt tooling (in either direction) and I'm not aware of any ports of Apple frameworks to Java similar to WinObjC's ports of those frameworks to Windows.

@optikos
Copy link
Author

optikos commented Feb 16, 2018

@devhawk, for now what I want to do is demonstrate the concept of a C++/RT family of C++/WinRT-inspired SDK projections into standard C++ that extrapolates the same app-domain-facing meta-class surface that C++/WinRT presents to app-domain source code for the Windows SDK so that:

  • C++/AndroidRT would present a very C++/WinRT-eqsue meta-class personality for the Android SDK to an app's source code
  • C++/ObjCRT would present a very C++/WinRT-eqsue meta-class personality for Apple's Objective-C frameworks for iOS or MacOS to an app's source code
  • and then the eventual grand finale: to an app's source code, C++/OverRT would present a very C++/WinRT-esque meta-class personality for a trans-OS UI API inspired by Xamarin.Forms in concept but for C++/RT instead and drastically relaxing Xamarin.Forms' harsh restrictions on absolutely no layout (e.g., no dynamically-appearing activity-indicator spinner) during lengthy Xamarin.Forms-internal redraw walks of the view tree. I also detest having substantially-different variants of ReactiveX libraries for each of C#/C++/F# (those 3 are substantially the same) versus Swift versus Kotlin/Java (those 2 are substantially the same). I also detest the harsh impedance mismatch between C# for UIs and C++ for high-performance backend processing, even with (mostly one-way) CppSharp. I am tired of cobbling everything together on non-Microsoft OSes with mylar tape and bobby-pins; I want everything much more Microsoft-ized via the obviously-very-wise leadership of C++/WinRT and (only-Microsoft-Research's-)ReactiveX.

As I mentioned over on the sibling Android-related issue #331, I am now thinking that Mono's Embeddinator-4000 might be the most expedient cppwinrt.exe-like thingy to demonstrate such a C++/RT for app development for UWP's, iOS's, MacOS's, and Android's respective SDKs as based on WinRT components for UWP via C++/WinRT and based on Xamarin.iOS, Xamarin.MacOS, and Xamarin.Android (Mono-).NET assemblies for the non-Microsoft UIs/OSes. This will incur the Xamarin/Mono overhead for now, but eventually bypassing Xamarin/Mono in each runtime to perhaps increase performance is something for future study after the initial proof of concept.

@optikos
Copy link
Author

optikos commented Feb 21, 2018

Embeddinator-4000's C++ feature that is indicated in its command-line help-text ends immediately with a not-yet-implemented exception when invoked.

@devhawk
Copy link

devhawk commented Feb 22, 2018

It would take a lot to convince me that a C++ based "trans-OS" solution would be any better than the existing tools out there like Xamarin.Forms or Cordova. Sure, it would be C++ instead of C# or JS. But the issues I typically have with such tools have little to do with language and everything to do how much harder it is to abstract away platform differences the closer you get to the user.

Instead of trying to abstract the entirety of the iOS or Android runtimes, have you considered a smaller scope proof of concept?

@optikos
Copy link
Author

optikos commented Feb 22, 2018

Of course. The would-be C++/OverRT‡ is what you are mentioning there—the analogue of Xamarin.Forms, but designed differently to be less like a cattle chute, and more like a bag of tools. Of course, C++/OverRT is not the •initial• proof of concept (any more than Xamarin.Forms was not the first step for Xamarin either). C++/ObjCRT might be the easiest 1st proof of concept, because the Objective-C runtimes in Apple OSes encodes a fairly rich amount of parameter names, analogous to .winMD in Microsoft OSes (or should I say, the various editions of a single OS: Windows 10). So the order might best be: C++/ObjCRT, then C++/AndroidRT, then insert whichever other OS Xamarin/Mono fully supports by that date here (e.g., Google FusciaOS, Samsung Tizen), then and only then C++/OverRT.

‡ renamed from C++/UniRT, because uni- too easily evokes Unix, even though historically the uni- of Unix actually is the Latin root uni- and its meaning of single/one/unified that was intentionally overtly criticizing the multi- at the heart of the Multics name. Multics was an OS that had multiples in places where Unix had singletons in 1970: threads per process (multiple for Multics; singleton for Unix), executable segments per process (multiple snapped DLLs for Multics; singleton text-segment for Unix), entry points per executable segment (multiple entry-point subroutines per DLL segment; single main() for Unix), and so forth. For modern people below a certain (retirement-)age, much of the Latin root uni- at the heart of the Unix name has been forgotten. Hence, not C++/UniRT. How about C++/panRT using the Latin root pan- to evoke “across”? Good Latin, but bad choice due to "to pan" in English is a verb that means to bash or give a bad review. How about C++/überRT using the German prefix über-? Good core spatial meaning, good German language, but bad at evoking some “über alles” memories of the past; also bad at evoking the competitor of Lyft too easily. So translate über- to English: C++/OverRT, a portable C++ library over all the runtimes‡‡ of various OSes.

‡‡ especially the •UI• runtimes of various OSes

Regarding your “take a lot of convincing“, the reason to enact C++/ObjCRT‡‡‡ is the same for C++/WinRT: to eliminate the so-called impedance-mismatch between the managed(-runtime) portion of a .NET app and the processor-native portion of that same app. The motivation for C++/ObjCRT is 100% congruent to the motivation for C++/WinRT on every aspect in transliteration. Each reason for C++/WinRT to exist has an analogous transliterated reason for C++/ObjCRT to exist. Please try to prove me wrong by trying to find a reason for C++/WinRT to exist on Microsoft OSes that is totally absent due to being without any transliterated analogue whatsoever in a C++/ObjCRT on Apple OSes. I am fairly certain that I can construe a rather-direct conceptual transliterated analogue on a C++/ObjCRT for a purported reason for C++/WinRT to exist that is truly unique to Microsoft OSes. The more that one constructs a line of reasoning for a C++/ObjCRT to not exist, the more one constructs much the same line of reasoning (transliterating from Apple-centric concepts to Microsoft-centric concepts) for C++/WinRT to not exist, and the converse: every reason for C++/WinRT to exist on Microsoft OSes begets a transliteration to Apple OSes for a C++/ObjCRT to exist. Or in fewer words in C++ syntax

class ReasonsForCppObjCRTbypassingMonoAndXamarinToExist : public ReasonsForCppWinRTtoExist
{
// ... snip all sorts of conceptual polymorphic overrides ...
}

‡‡‡ that eventually does not depend on invoking runtime functionality via Xamarin.iOS/Xamarin.Mac. Initially in the proof of concept, perhaps it would be expedient to incur the overhead of Mono & Xamarin to show the proof of concept, then (at the 2.0 rewrite) bypass invocation through Mono & Xamarin when invoking the OSes runtime. That bypass of Xamarin.iOS/Xamarin.Mac is the step that would bring the hope of C++ achieving processor-native level of performance that could compete directly head-to-head speedwise with Objective-C on iOS & on MacOS with the Swift efficiencies of compile-time elimination of Objective-C's run-time selector look-up and caching thereof. Hence, C++/ObjCRT could conceivably out-perform both Objective-C and Swift on Apple OSes via removing the speed-robbing language-design/features of each of Objective-C & Swift.

(Please see the analogous comment on the sibling C++/AndroidRT comment.

@devhawk
Copy link

devhawk commented Feb 23, 2018

Of course there are "transliterated analogues" for a technology like WinRT to exist on other platforms. But that doesn't make it easy or feasible. Both iOS and Android have settled on a language strategy of only supporting a small set of "platform native" languages - ObjC & Swift on iOS, Java & Kotlin on Android - without appearing to give much thought or care to supporting languages beyond that. Both platforms support C++, but as what seems like a second class citizen. Workaround exist of course, but without the platform vendor's involvement, the amount of work to expose the existing platform APIs to C++ seems like a huge amount of work.

Even if Apple and Google decided they wanted to treat C++ as a first class citizen on their respective platforms - and decided to use WinRT style technology to get there - that wouldn't get you any closer to an "uber" API for mobile apps as you describe. You'd end up with something like the Xamarin ecosystem - build your business logic in a component that can be shared across your mobile apps and build separate per-platform apps. Maybe a Xamarin.Forms-style framework would emerge, but it would have the same issues that Xamarin.Forms has - it wouldn't be able to expose the power of each underlying platform, leaving developers to either target a lowest common denominator or write a lot of platform specific code in their so-called "uber" mobile app.

I hope you understand that I'm sympathetic to some of what you're writing about. I just want to see any "boundary pushing" effort scoped down to be achievable.

@optikos
Copy link
Author

optikos commented Feb 23, 2018

@devhawk, I would say that C# is •the• one & only 2nd-class citizen on Android and on iOS & MacOS via the impressive (brute-force) efforts of Xamarin/Mono. I would say that C++ is less than a 2nd-class citizen. Without stepping on too many political toes in the currently-immigration-charged environment in the USA & in the EU, it is as though C++ is a green-card resident immigrant (noncitizen), even lower in the pecking-order totem pole than C# via Xamarin/Mono/.NETcore. What I am advocating is that C++ get up to being a card-carrying member of the 2nd-class citizen club along with C# on Android and iOS.

(And I'll hardly mention much of RemObjects' efforts to provide all of {Java, C#, Swift, Object Pascal} across all of {UWP, iOS, MacOS, Android JVM, Android processor-native, desktop JVM}. RemObjects' approach in their Elements confederated compiler is to meld all the open-source compilers of those languages into one superdooper compiler executable that shares some sort of AST unification among the confederated languages, permitting each language to deeply map its feature-set into each of the other languages on the fly. RemObjects' approach is not really an •outward•-facing/generating language •projection• in the C++/WinRT sense or the Embeddinator-4000 sense. RemObjects' approach is more •inward•-facing/essence-of-oneness within the compiler: language •injection•, injecting the AST of one language's APIs into the AST of another confederated compiler source-code-base in the same executable via a deep construct-to-construct mapping at the AST level. Another hallmark of the RemObjects' approach is to eradicate gross “omissions” of feature-set in one language by borrowing another language's feature-set, so that C# gets Swift's ARC, Swift gets C#'s await & Java's & C#'s external, Java gets ARC & await, they all get Oxygene's/Object-Pascal's aspect-oriented programming (AOP) weaving, they all get Objective-C's multipart subroutine names, they all get Swift's not-nullable types & ? syntax, and so forth. The RemObjects approach is uninteresting so far for this GitHub-issue because thus far RemObjects has shown no interest in bringing Clang [and thus C++] into the Elements confederation of compilers that share each other's guts with the other languages.)

@devhawk
Copy link

devhawk commented Feb 23, 2018

I don't want to argue language citizenship status, but I will agree that C++ doesn't have access to significant parts of the iOS and Android platforms.

However, I don't see the value in investing to get C++ to the same level of platform access that Xamarin has. It would be an enormous amount of work to replicate what Xamarin has done over the past 13 years. More importantly, Xamarin already exists.

C# is a great language for building apps. It's productive and performant. There's no question C++ is more powerful and really has closed much of the productivity gap relative to C#. But it's also more finicky and verbose. I don't think C# a good choice for system development - but not because of any issue with the language but rather because I don't believe non-deterministic garbage collection is a reasonable foundation to build a system on.

Let me ask you a couple questions:

  • What are the problems you have with Xamarin, in particular Xamarin Forms?
  • What about your proposed "uber" C++ RT solution would solve those issues?

@optikos
Copy link
Author

optikos commented Feb 23, 2018

I think that the iOS bar charts in this WWWpage are very revealing:

  1. Objective-C selector look-up & caching is less performant than compile-time-generated vtables.
  2. In some scenarios, Objective-C's selector look-up & caching dominates, but in others Xamarin.iOS's Mono ‘dual-stack’ overhead dominates. C++/ObjC 1.0 would eliminate Objective-C's selector look-up & caching, which is Swift's main performance-gain claim-to-fame too. C++/ObjC 2.0 would eliminate Xamarin.iOS's Mono dual-stack overhead.
  3. Despite Apple's general claim that Swift is 40% faster than Objective-C, there exists a chronic set of symptoms perennially popping up here & there like Whack-a-Mole that Objective-C is actually faster than Swift, even in recent Swift in 2017. Perhaps Swift's LLVM-backend optimization developers can hardly keep up with Swift's front-end feature-set developers (or something similar to that situation), which would correct itself over time if an app refrained from utilizing new Swift language features to stop being on any bleeding edge. (Conversely, how many LLVM-backend optimizations recognize only the Swift idiom to optimize but fail to recognize the directly-analogous Objective-C idiom to optimize? As Swift gets more optimized, some substantially-similar Objective-C idioms might be benefiting too, improving Objective-C's performance, so perhaps occasionally no net gain for Swift vis a vis any other Clang-based language, such as Objective-C or even perhaps a C++/ObjC.) But the jury is still out whether Swift's chronic 4-year-running not-quite-perfectly-impressive performance is due to transient issues in releases of Swift due to all the feature-set churn, or whether it is due to something more fundamental & quasi-permanent.

The qualitative problems that I have with Xamarin.Forms is fundamental to its rendering phase: no ability (even for Xamarin itself) to have any variant of an activity-indicator spinner while rendering complex UI layout that take too long. StackOverflow and Xamarin forums have a multitude of requests to solve this problem specifically of how to display such an activity-indicator. Solutions exist only for when the lengthy operation is •not• a Xamarin.Forms-internal walk of the view-tree, such as a database retrieval or a network communication.

The quantitative problems that I have in general with Xamarin.Forms is its sluggish performance of its rendering. Numerous Xamarin.Forms forum postings and numerous Xamarin WWWpages discuss ways of performing variants of loop-optimization to get app-domain operations out of Xamarin rendering walk of the view-tree. But this does not improve the internal sluggishness of Xamarin.Forms itself. This does not mitigate in any way the aforementioned ability to help bail out the embarrassment by putting up an activity-indicator when the app developer knows that the triggered rendering is complex enough to cause annoying-to-human-users-of-the-app latency. From human user touch on the device all the way to custom-rendering a rectangle, there is really no meaningful way for the app source code to do anything but serve the Xamarin.Forms rendering operations as servant and wait for the benevolent dictator to finish his seemingly leisurely stroll throughout the entire grounds of his vast estate. And this is on UWP and iOS. Performance matters are far far worse on Android because of the additional higher overhead penalty of the big thick Mono stack outside the JVM JNIing the big thick Java stack inside the JVM. (A C++/AndroidRT 2.0 after bypassing Xamarin.Android to do the JNIing would eliminate at least 1 of those 2 big thick stacks.)

I consider the primary architectural flaw of Xamarin.Forms to be the relegation of accessing the underlying SDK only during actual redraw after walk of the tree of Xamarin.Forms views. The underlying SDK's objects should be available by drill-down during the walk of the tree of Xamarin.Forms views, not postponed until after the entire walk, quarantining accessing the underlying SDK's objects only during redraw by a custom renderer. The architecture should permit a shared responsibility between the Xamarin.Forms-esque infrastructure and the app source code, so that the the app source code can get involved with the walk of the view-tree and tweak it, interact with it, bail out its embarrassing performance with at least displaying an activity-indicator, and even optimize it. The current Xamarin.Forms architecture is very much handoff-handback, as if throwing a gigantic red electrical switch (or railroad switch) between mine/app versus yours/Xamarin.Forms. Xamarin.Forms disrupts the naturally-expected mental flow of an OO developer: hey, Xamarin.Forms, you abstracted the OS SDK's X to be a directly-equivalent Xamarin.Forms X-prime, so let me have a little access (other than custom-renderer total washing of your hands) to the X that is underlying the X-prime. Not only is the X not public in the X-prime, X is not private within X-prime either. Xamarin.Forms models the X as not even existing/mapped to the X-prime until rendering. X is an astronomical secret to X-prime until the final step of rendering. Total full divorce between the X and the X-prime. It is as though 2 spouses are married but are kept entirely away from each other most of the time, only to see each other when conceiving offspring, and then immediately imprisoned away again from each other separately until the next rendering of offspring. I spend 90% of my time fighting Xamarin.Forms' architecture, bailing out Xamarin.Forms performance, and extending abandoned open-source extensions of Xamarin.Forms that try to teach it to interesting/nontrivial UI/UX tricks. (Other than for apps that are literally nothing more than the provided example apps,) I gave up on Xamarin.Forms; developing an analogous UI for the same app 4 times in Xamarin.iOS, Xamarin.Mac, Xamarin.Android, and UWP.NET is so much faster than fighting Xamarin.Forms.

But then I regret that I am expending 4 repeats of effort to get less-than-Swift, less-than-Objective-C, less-than-Java, less-than-Kotlin, less-than-C++/WinRT performance via Mono's C# stack, so then I forego Xamarin.iOS, Xamarin.Mac, Xamarin.Android, C#.NET, and thus C# altogether, writing the 4 repeats of UI with substantially similar UX in Swift on iOS, Swift on Mac, Kotlin on JVM, and C++/WinRT on UWP, with C++ backend processing as much as possible as so-called “business logic”. But then I run into the needless gratuitous variance among each of those language's different ports of the ReactiveX library {RxKotlin, RxSwift, RxCpp}, which further disrupts/erodes some of the ability to write substantially the same verbatim app with the same C++ backend libraries with the not-quite-the-same ReactiveX framework. One would hope that the 4 intended-to-be-verbatim apps would differ in only SDK and minor language features & nits (plus menus/window-frames on nonmobile devices versus the lack thereof on mobile devices), but in practice the 4 apps' source code diverges vastly more than I would like it to.

Having C++/WinRT, C++/AndroidRT, C++/ObjCRT, and RxCpp (and porting RxCocoa & RxAndroid to be RxCpp-based, if I must) would solve in the long-run most of my performance challenges, would solve prior to that all of my 4-app source-code divergence challenges, and would solve the impedance-mismatch between C++ backend-processing libraries versus each different UI/UX language & runtime. And, btw, that is typically 3 different OO-high-fidelity‡ solutions for the impedance mismatch: C++-versus-Kotlin, C++-versus-Swift, and C++-versus-C# (if using C# for UWP instead of C++/WinRT or C++/CX), which causes further divergence among the intended-to-be-but-fails-to-be-verbatim 4 apps. Oh, and it will soon be 5 apps, once Tizen devices start showing up in large numbers in industrialized nations.

‡ not C nonOO, not SWIG

@devhawk
Copy link

devhawk commented Feb 23, 2018

Sorry, I know very little about UI frameworks. So your fairly deep description of Xamarin's architecture and the problems you're seeing is lost on me. I'm absolutely sure the issues you describe are real. I'm also pretty sure that the issues you describe are intrinsic to abstracting something as complex as the primary UI framework on three separate platforms, each of which targets a separate programming language.

I seriously doubt that switching to C++ will solve that problem.

Any chance you have a code example of this scenario you describe: "writing the 4 repeats of UI with substantially similar UX in Swift on iOS, Swift on Mac, Kotlin on JVM, and C++/WinRT on UWP, with C++ backend processing as much as possible as so-called “business logic”.". I'd love to see how you're connecting Swift and Kotlin to C++ via Rx.

@optikos
Copy link
Author

optikos commented Feb 23, 2018

Well, using Rx across the UI-to-backend boundary is the stretch-goal for a C++/RT-family language projection, so that is not current technology.

But minus automatic generation of Rx (i.e., hand-crafted in the IDL instead), I use Djinni to generate Java and Objective-C with Swift bridge.

@devhawk
Copy link

devhawk commented Feb 23, 2018

And then you use Rx to connect the UI to the bridged C++ code?

@optikos
Copy link
Author

optikos commented Feb 23, 2018

The Rx sequence unfortunately comes to a screeching halt at the C++ bridge, needing a subject/observer-observable/enumerator-enumerable across the C++ bridge, adding yet another degree of impedance mismatch. The backend-processing seems to fall into the category quite often that is better addressed by the Ix side of the house than the Rx side of the house (or by backpressure in the Java/Kotlin peculiar take on Rx)—hence, many of my aforementioned per-OS divergence woes that I dream of smoothing out with a less-cobbled-together more-elegant C++/RT-family solution.

@devhawk
Copy link

devhawk commented Feb 24, 2018

WinRT doesn't define IObserver/IObservable unfortunately.

@optikos
Copy link
Author

optikos commented Feb 24, 2018

RxCpp's Rx & Ix for standard C++ only, then handcraft your subject/observer-observable across your backend-processing component's DLL/.winMD interface, then project into standard C++ via cppwinrt.exe, then glue code to the Rx or Ix sequence to the language projection.

@optikos
Copy link
Author

optikos commented Feb 26, 2018

@devhawk, regarding the flaws of Xamarin.Forms being “intrinsic to abstracting something as complex as the primary UI framework on three separate platforms”, VIPER software architecture (instead of MVC or MVVM) clearly refutes that claim. Please take note of the “owns and sends user actions” relation in the VIPER UML diagram in that linked WWWpage and to a lesser degree the “updates” relation in the opposite direction. In VIPER, not only does X and X-prime have on-going never-divorced relations, each X owns the corresponding X-prime. In VIPER View→Presenter relations, each X essentially says to each X-prime, “Hey, my other half, go do portable UX stuff that corresponds to my such-and-such non-portable highly-specific-to-UI-framework behavior of this OS.” In VIPER Presenter→View relations, each X-prime essentially says to each X, “Hey, my other half, go do nonportable UI-framework stuff for this OS to accomplish my such-and-such portable UX behavior.” VIPER's nonportable-UI-versus-portable-UX difference between MVVM versus VIPER captures my fundamental criticism of Xamarin.Forms' architecture.

@devhawk
Copy link

devhawk commented Feb 26, 2018

Is there a VIPER based cross-platform UI framework? Are there cross-platform apps that use VIPER? I'd love to see some source code.

@optikos
Copy link
Author

optikos commented Feb 26, 2018

I am not working on an open-source app. My company's work is closed-source. It does not take very much imagination; the outcome of VIPER is fairly direct: In the VIPER architecture, all VIPER classes other than the VIPER Views are eligible (and encouraged) to be cross-platform. The VIPER Views of an app quarantine the OS's/SDK's UI proprietaryness, whereas VIPER Presenters free the UX to be cross-platform at the “uber” level, to use our earlier term. Over time, taken together, the various apps' VIPER Presenters are a strawman beginning of what a quite-different competitor to Xamarin.Forms would look like in C++. Within the VIPER Presenters (and the Routers, when considering what navigation & dependency injection provides in MVVM), every app developer develops that app's own perspective on what cross-platform UX constructs & behaviors look like, separate from a specific OS's/SDK's UI. Indeed, to the point of this original issue and subsequent discussion, the VIPER Presenters & Routers (and of course obviously the Interactors and Entities) can be thought of as a backend-processing library, written in standard C++, leaving only the VIPER Views written in OS-/SDK-specific languages & runtimes & frameworks as Java, C#, F#, C++/CX, C++/WinRT, WinRT components, .NET, Objective-C, Swift, Kotlin, Mono, JVM, XAML, and so forth. Once cross-platform UX design is coded in portable C++ in today's VIPER approach, then the natural goal in the future is to have the OS's/SDK's nonportable UI be coded in •nonportable• C++ code specific to that SDK. And then once we were have that in the future, the the next goal in the future is take the cycles of learning from the modest amount of abstraction in all the plethora of Presenters harvested from many apps to arrive at a Xamarin.Forms-esque portable C++ “uber” replacement for the vast majority of the VIPER Views of interOS-/interSDK-(onto‡-)mappable UI constructs & behaviors, leaving only the one-off unique-capability UIs peculiar to only one OS/SDK as the remaining few nonportable-C++ classes in the VIPER Views. But because this factoring was arrived at via VIPER architecture instead of MVVM architecture, the similarities between Xamarin.Forms and this portable-C++-UI replacement of previously-nonportable-C++ VIPER Views are in the conceptual domain of goals & missions‡‡, not at the blow-by-blow detailed analysis of their technical guts of how those missions & goals are accomplished.

‡ not necessarily one-to-one

‡‡ e.g., display a master-detail drill-down-tree; display a carousel of photos; display a pull-down refreshable newsfeed; display a swipe-right/swipe-left list

@devhawk
Copy link

devhawk commented Feb 27, 2018

So if you own the app, why not do exactly what you suggest but use C# instead of C++? Wouldn't the process and outcome be basically the same?

  • Define C# interfaces for each of your views
  • Build the non-view components of your app in C# against the .NET Standard specification
  • Build the view components of your app in C# using Xamarin.iOS, Xamarin.Android and UWP
  • Over time, harvest common view patterns into common shared implementations and publish them as an alternative to Xamarin.Forms

@devhawk
Copy link

devhawk commented Feb 27, 2018

Also, this sentence totally threw me:

Once cross-platform UX design is coded in portable C++ in today's VIPER approach, then the natural goal in the future is to have the OS's/SDK's nonportable UI be coded in •nonportable• C++ code specific to that SDK.

I don't understand this approach at all. Building a good + portable UI framework abstraction is the hard part. (By "hard" I mean "probably not even possible". I don't agree that using the VIPER software architecture in any way "refutes that claim".) Why would you spend the time and effort to build a portable UI framework if your "natural goal" is to build non-portable UI.

Even if you were hell bent for leather to use C++, wouldn't it be easier to just build C++ bindings for platform native UI components on iOS and Android? (Windows already has them.) I mean, even though we clearly disagree about the level of difficulty in building a good + portable UI abstraction framework, clearly it would be easier to not build it right,?

@optikos
Copy link
Author

optikos commented Feb 27, 2018

@devhawk, in response to my pointing out the severe architectural defect of X-prime having only an extremely-transient relation with X only during rendering (where X-prime doesn't merely hide its X private:ly, but rather X is kept secret & separate from X-prime), you wrote “I'm also pretty sure that the issues you describe are •intrinsic• to abstracting something as complex as the primary UI framework on three separate platforms …”. The VIPER architecture's “owns and sends user actions” relation clearly is an overt direct refutation of your (and Xamarin.Forms designers') claim that X must be kept secret & separate from X-prime except for a transient temporary conjugal visit during rendering. X-prime here stands for each Xamarin.Forms' cross-platform-abstracted UI view, but also X-prime is analogous to each VIPER Presenter. X here stands for source code in Xamarin.Forms' renderers that itself invokes each nonportable OS/SDK UI element, but also X is analogous to each VIPER View. Clearly, VIPER does not keep X locked up in some far away secretive castle dungeon most of the time, except for occasional conjugal visits during rendering, but Xamarin.Forms does. Clearly, each VIPER View and its corresponding VIPER Presenter have a never-severed reciprocal pair of “owns and sends user actions” and “updates” relations that arguably Xamarin.Forms completely lacks in the static/permanent sense (or should I say, exists extremely transiently as something unseemly only during the conjugal visits during rendering). Clearly, this is a black & white, day & night difference that I am exposing. Clearly, VIPER has something useful (to the VIPER way) that Xamarin.Forms lacks. It is a difference that makes a difference. The Xamarin.Forms lack thereof is not inherent to the problemspace, as you claim. The very fact that VIPER has something that Xamarin.Forms lacks proves by counterexample that the lack (which you claim is intrinsic to the problemspace, and thus part of all solutions) is not dictated by the gods of fate & reality & reason. There does exist another way that is quite different, which VIPER clearly reveals.

@optikos
Copy link
Author

optikos commented Feb 27, 2018

@devhawk, regarding your “why not … use C# instead of C++?”, I would say that the answer-set is the 1-to-1 & onto mappable to “why not just forget about C++/WinRT and use C# instead?” A case in point is that utilizing C++ for backend-processing libraries and C# for the UI/UX means that the impedance mismatch of the C++/C# boundary erupts into app-domain source code as handcrafted work-around (even if one uses a little djinni-esque thin IDL-to-source code generator, because the IDL needs to be handcrafted and the glue code needs to be handcrafted), whereas in the aforementioned C++/RT-family approach, the C++/runtime boundary is buried within automatically-generated infrastructure instead of strewn horizontally throughout app-domain source code. Because the C++/C# boundary lacks a rich set of aware-of-both-sides refactoring or aspect-oriented tooling, tweaking the C++/C# boundary for performance or design reasons is forever a laborious manual effort extending across the entire façade. Conversely, because the Win/RT-family approach would be code-generator-based (e.g., analogous to today's wincpprt.exe), the C++/runtime boundary can be tweaked for any reason (e.g., performance, semantic behaviors, new language features, projecting a new DLL format) as easily as it is to write a little bit of new code in the code generator, then invoke msbuild or make.

@devhawk
Copy link

devhawk commented Feb 27, 2018

I'm no expert in building user experiences. My experiments with Xamarin.Forms haven't made it past the "Hello World" level and I'd never heard of VIPER before you mentioned it. I don't even understand why you conflate Xamarin.Forms and VIPER - one is a software architecture and one is a software library, so it feels to me that you are comparing apples and oranges. If you can show me some actual code to demonstrate your opinions about VIPER, I'll be happy to take a look.

As for C++/C# - an area where I have much more experience - it comes down to app ownership. Remember, I said, "So if you own the app, why not do exactly what you suggest but use C# instead of C++?" In the Windows platform, by definition, we never "own the app". In the Windows platform, we want to meet developers where they are most comfortable using the tools and languages that they want to use. Likewise, we want the same thing for Project "Rome", which is why we ship SDKs for Windows, iOS, Android, and Xamarin.

@optikos
Copy link
Author

optikos commented Feb 27, 2018

Not to be too blunt, but I (and quite a few other C++ developers) want to use C++ everywhere, not C# everywhere, not C++/CX on only UWP, and even not C++/WinRT on only Windows components. I would like to think that we C++ developers who think this way are part of the they of which you speak, as being most comfortable and preferring certain language's natural characteristics & overheads (or lack thereof). Project Rome is most excellent at providing a hand-off SDK among disparate OSes. Thank you, everyone at Microsoft who make Project Rome possible! What I envision for C++/RX would be pointed at the one of the iOS, Android, or Xamarin SDKs to language-project a façade to C++, then C++ would also have an SDK to Project Rome for each of the other OSes. Btw, I think that Project Rome should have an SDK for MacOS and Tizen eventually; conceivably that is implicit in the Xamarin{.iOS, .Android, .Mac, .Tizen} SDK. There isn't really Xamarin per se; there is Xamarin.iOS, Xamarin.Mac, Xamarin.Android, and Xamarin.Tizen. And hand-off to the TV & auto(motive-dashboard) variants of those OSes as well.

Xamarin.Forms (as well as every other body of software since software was invented) has some form of software architecture (even if that software architecture is chaotic big ball of mud). So, yes, one can compare Xamarin.Forms' MVVM-centric software architecture with VIPER software architecture. No “conflation” needed, because it is an architecture-to-architecture masterplan-to-masterplan apples-to-apples comparison. Likewise, one can compare an actual extant physical building's architecture with the blueprint of another differently-designed building's architecture to see whether one building serves its purposes better or whether one is maldesigned; no conflation needed.

@devhawk
Copy link

devhawk commented Feb 27, 2018

Go ahead and be as blunt as you want. I'm cool with it.

The whole reason we build WinRT in the first place was to enable developers to use the tools they want. So I totally get wanting to use C++ everywhere. I argued strongly against C++/CX at the time. To be fair, we ended up in a better place now (i.e. C++/WinRT) than we would have if we had integrated WinRT into the VC++ compiler the way it's integrated into the C# and JS runtimes.

It's too bad that Apple and Google don't share Microsoft's goal of fully empowering C++ developers on their platforms. However, there's little I or the C++/WinRT team can do about that.

Thanks for your kinds words about Project Rome. There are lots of things we'd like to do, but as you are no doubt aware realities of available resources and time when it comes to pulling items off the backlog. I'm not aware of much interest in Project Rome for Mac or Tizen, but feel free to file an issue on our GitHub repo

@optikos
Copy link
Author

optikos commented Feb 28, 2018

I think that we have explored quite a few avenues of this potential future for an extrapolation of C++/WinRT to a C++/ObjCRT as part of a C++/RT family of C++/WinRT-esque C++ language projections for other OSes' SDKs in other OSes' runtimes, and perhaps eventually a C++/uberRT to permit writing portable app-domain source code for those UI constructs that all other OSes' UI/UX has in common (vaguely analogous to Xamarin.Forms, but perhaps with a drastically different software architecture). Along some of these avenues, it seems Mono's Embeddinator-4000 might be the furthest along to serve a cppwinrt.exe-like functionality for C++/ObjCRT. Extending Embeddinator-4000 (or merging the nonWindows portion of WinObjC into Embeddinator-4000) might be the path of least resistance for anyone seeking a C++/ObjCRT. It will be interesting to see what Mono eventually generates as its language projection for C++ for Objective-C runtimes in Embeddinator-4000; work had been progressing there somewhat during 2017. In one potential future, perhaps that Mono work (also Microsoft-based) will borrow heavily from C++/WinRT. Or in another potential future, perhaps Mono will devise a drastically different family of C++ language projections, one of which might be to Windows 10 editions, hence forming a(n unfortunate) competitor of sorts to C++/WinRT.

Thank you everyone (especially Kenny Kerr) for patiently allowing an at-time free-wheeling discussion of a potential future without closing this issue prematurely. For now, I am going to close this issue, so that if any aspect of this broad topic arises again by anybody, new issue(s) can be opened on finer granularities of C++/WinRT-extrapolated-to-other-OSes topics.

@optikos optikos closed this as completed Feb 28, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants