Hi,
As you’ve probably guessed by now, I’ve been spending quite a bit of time on the website and docs system.
This involved a crash course in wordpress, but I think I’ve mostly got my head around it now. I’m pretty pleased with the results, although it certainly still has a ‘designed by a programmer’ look about it. But that’s OK – it’s a programming site after all! With a bit of luck, once monkey2 is a bit more widely used some more professional looking sites will popup. Still, I like having a site that *I* know how to tweak and will (hopefully) be low maintenance.
I’ve re-enabled post comments for the site and you can now also post comments on doc pages. This is strictly for testing purposes right now. I will probably scrub all the comments before the ‘final’ docs are uploaded so don’t get too carried, but please do feel free to give it a go!
You can also edit comments after you’ve made them. However this side of things is a bit wonky, as wordpress insists on editing them in the admin page, so you don’t get the nice visual editor. I ‘sort of’ got it going, but it was ‘double escaping’ the posts or something weird so I gave up. Will revisit this later.
But it hasn’t all been web fun and games. Doing the docs also forced me to fixed something I was kind of dreading – aliases. Up until recently, aliases have been ‘resolved’ immediately when their symbols are looked up. For example:
1
2
3
4
|
Alias Vec3f:Vec3<Float>
Global CameraPosition:Vec3f
|
The actual ‘type’ of CameraPosition as far as the compiler is concerned is Vec3<Float>, since the alias is resolved when the type ‘Vec3f’ is worked out. But this means the docs are ‘wrong’, ie: you get this:
1
2
|
Global CameraPosition:Vec3<Float>
|
Ok, you could argue that’s just as correct, and in this case it’s not so bad. But aliases are often used to simplify complex types, eg:
1
2
|
Alias OpenFunc:Stream( proto:String,path:String,mode:String )
|
Having ‘OpenFunc’ expanded to its full type everywhere in the docs just didn’t do it for me!
So it’s fixed now, although it involved writing a ‘proxy’ class which can be quite tricky (esp. when done ‘after tha fact’), so there *may* have been a few issues introduced in the process, although everything *seems* to be fine…
While I was in the guts of the alias system, I also added generic aliases. This was also partly docs inspired, but mostly because I wanted to clean up the ‘StringStack’, ‘StringMap’ convenience types (which I use a lot). These used to be implemented with something like this:
1
2
|
Class StringStack Extends Stack<String>
End
|
However, this is kind of nasty/cheating (the empty classes it also looked ‘weird’ in the docs). It mostly works, but in reality a StringStack is *not* a Stack<String>. This becomes an issue when you try and do something like:
1
2
3
4
5
|
Local buf:=New StringStack
buf.Push( "X" )
buf.Push( "Y" )
buf=buf.Slice( 1 ) 'ERROR!
|
The last line gives an error because ‘Slice’ is a member of Stack<T> and returns a Stack<T>, not a StringStack, so it can’t be assigned to buf. Even a downcast wont help.
So StringStack and co. are now implemented via Alias, eg:
1
|
Alias StringStack:Stack<String>
|
Which allows buf=buf.Slice( 1 ) to work no problem.
But I ran into problems implementing StringMap as an alias, which used to look like this:
1
2
|
Class StringMap<V> Extends Map<String,V>
End
|
The problem here is that a simple alias isn’t enough, because there is still the unknown type parameter ‘V’. The solution is a generic alias:
1
|
Alias StringMap<V>:Map<String,V>
|
This can be used in exactly the same way the old ‘extends’ version could, eg:
1
2
3
|
Local myMap:=New StringMap<MyClass>
myMap["root"]=New MyClass
...etc...
|
I also spent a bit of time on the extern system. You can now #import local “.dylib” and “.framework” libs on Macos, and the compiler tries a bit harder to think up a useful symbol for extern decls that are declared without one. For example, this…
1
2
3
4
5
|
Extern
Class C
Function Test()
End
|
…now generates ‘C::Test’ as the native symbol for ‘Test’. It used to just use the decl identifier, which in this case would have been plain ‘Test’ which was pretty much useless. Note that if you explicitly declare a symbol using =”blah” syntax, mx2 doesn’t touch it at all.
Enums are a tricky case. There several ways to declare enums in c/c++, so one system that deals with all of them is not easy, but I’ve given it a shot. By default, this…
1
2
3
4
|
Enum E
V1
V2
End
|
Will map V1 to ‘V1’, V2 to ‘V2’ etc. This is to handle c/c++ enums which are actually not added to the enum scope, but the enum’s outer scope. Similarly, this…
1
2
3
4
|
Enum E="C::E"
V1
V2
End
|
Will map V1 to ‘C::V1’ and V2 to ‘C::V2’.
You can also declare ‘anonymous’ enums using this kludge…
1
2
3
4
|
Enum E="E::"
V1
V2
End
|
This will map V1 to ‘E::V1’ and V2 to ‘E::V2’, BUT it will use ‘int’ as the enum type, not ‘E’. This is to handle c++ code such as:
1
2
3
4
5
|
namespace E{
enum{ //note: no actual enum type declared!
V1,V2
};
}
|
Ideally, all this interface code should really be automatically generated by some cool tool (llvm lib looks promising), but until such a tool exists I think these little extras will be worth it.
So, what next for monkey2?
My immediate goal is get a usable debugger going, and that means resurrecting the gui/graphics system.
The debugger will, for now, remain based on the simple approach I took in bmx – ie: code as added to the translated output to store current function/statement location. This side of things is already working to a degree – in debug mode you can now use GetDebugStack() to find out where you are in the stack. However, debugging without *some* kind of gui is no fun at all so getting mojo working again is a proprity right now. And yes, debug info WILL include globals this time ’round!
This style of debug info is not the most efficient, and ultimately it’d be nice to somehow translate c++ debug info to monkey debug info, and parse lldb debugger output etc. But given my limited knowledge of either c++ debug info or lldb, that’s a relatively big job that I wont be attempting right now.
Besides, this ‘hacky’ approach to debug info has some benefits – it can be used to do a simple profiler, custom code can be called every function/statement etc. And an interesting idea: it should be possible to track the last N statements executed in a cicular queue, and find out how code got to a particular statement. You wouldn’t be able to ‘undo’ var changes, but just seeing what the last N statement executed before a crash might be useful?
There have also been a few questions asked recently about how monkey2 will work on ios/android. And the truth is I don’t know yet. My current thinking is for monkey2 to generate a static (or dynamic) lib that contains all the app code (and only needs to expose a bbMain), that can be dumped into a ‘target project’, ie: an Android Studio or XCode project. The SDL code might end up in the target project too, so it can be properly initialized at the right time and hacked if necessary to deal with app suspension or whatever.
I also think target specific code and libs such GooglePlay, AppStore, Ads etc should be in the target project, NOT monkey. These often have weird requirements for adding them to projects such as having to modify linker settings etc, and while I tried in monkey1 to modularize this stuff I think ultimately it just didn’t work very well.
I also want to avoid the situation I got into with the ‘app config’ settings stuff in monkey1. This basically allowed you to modify a limited subset of project properties (such as android manifest settings or ios info.plist vars) via ‘#SOME_VAR=SOMETHING’ in monkey code. The compiler then attempted to hack these settings into the target project using a variety of unholy techniques.
This was based on my initial flawed thinking that ‘it would be nice if the user only had to deal with monkey’. But it just wasn’t worth it – it was a nightmare to maintain and IMO just made it harder when you ineveitably needed to add something to the target project that wasn’t supported via app config settings. So in monkey2, if you want to modify the android manifest or ios info.plist, you will need to do so OUTSIDE of monkey2. The simplest way being of course to use android studio or xcode – which are designed for exactly this stuff.
Bye,
Mark
Some considerations:
I think there are some ‘basic & commons’ settings valid both for iOS / Android /Whatelse (ie: SCREEN_ORIENTATION, APP_LABEL, APP_NAME, VERSION etc) that should be supported natively by MX2 (if something under a certain target isn’t required, that setting is simply ignored).
adding something in the IDE to access the iOS/Android studio settings would be very useful (without open another IDE/application etc, just to set some parameters…)
I would leave ‘out’ just things are really complex or not full supported/not standard etc
with only 2 mobile OS (Android and iOS – Windows Mobile/10/x??? is losing market day by day) it seems a strange move (in MX1 you tried to support everything PSP,Ouya! etc,…)
I’ve not clear if mx2cc should or not handle directly point (1) or should use another little (extern) application (like mserver in MX1) to ‘translate/update’ parameters in the android-studio/Xcode settings.
Cheers
I appreciate what you’re saying, but I disagree. As soon monkey starts ‘twiddling’ with the android.manifest or info.plist files or project files, things suddenly get a whole lot more complex.
For example, on android I ended up creating a ‘templates/android.manifest’ file purely for this reason, ie: so monkey could modify the template manifest and generate the ‘real’ manifest. I couldn’t just do this with ${BEGIN} ${END} ‘comments’ in the real manifest (the way I do with main.cpp) because for some reason XML doesn’t allow comments in the ‘<‘ ‘>’ tags!
But this just ends up confusing things – people edit the real manifest file not knowing about the template, so their edits are overwritten; and the android project can’t really be edited with anything else.
As for changing APP_LABEL, APP_NAME etc *after* the project is created, this is a nightmare. To do this you need to hack/change things at multiple places in the project in really nasty ways. I tried with ios projects but gave up. There may be a tool around that does this, or perhaps one could be written in monkey2, but I don’t think this should be part monkey2’s ‘core’ responsibility.
I would much prefer that monkey2 (and users) dealt with a ‘clean’ android studio or xcode project, that monkey2 just dumps some code into. This way, users can use the *full* set of tools available (and designed) for configuring and maintaining these projects, without monkey2 having to perform 1001 confusing hacks to achieve exactly the same thing. This means users can’t do everything *in* monkey2, but it does mean they can at least do *everything* somehow.
Sorry, turned into a bit of a rant!
I didn’t expect I’d say this, but I actually agree with Mark on this point. I publish on several Android-based platforms, on iOS and on Windows Phone. Yes, it is time consuming, but entirely manageable through the respective IDEs. Current Monkey1 style native project building is great when it works, but the problem is that it keeps breaking: either I have to use a third-party lib/SDK that integrates in a weird way, or a well-known SDK changes so much it becomes incompatible with the Monkey build system (as it happened with AdMob for iOS). In the end, I have to do things manually anyway, and sometimes the Monkey templates have to be modified to stay out of the way.
The way Monkey2 is going, it isn’t going to be a beginner’s language anyway, so a certain degree of knowledge and skill would be expected from the users. Might as well keep the target project templates lean.
There is a deeper problem for third party lib integration. From my Monkey1/Android experience, I had to modify the standard targets on a number of occasions to allow my Monkey code to either receive callbacks such as onActivityResult, or to be able to insert something into the activity life cycle methods (onStop, onDestroy, etc.). It would be helpful if Monkey2 projects had “hooks” for stuff like this wherever possible, if only as empty stubs. Same applies to iOS and probably other platforms.
Ok, it seems there are valid reasons for this choice… If I change my point of view I could understand that a different tool (for iOS or Android) could ‘break-up’ the chain…
I have no clear what MX2 will ‘put’ in the Android-studio (or iOS) and if and what should be ‘completed’ manually by the user in the ‘next-step’. My laziness hopes that the MX-IDE will handle *a lot* of this things :D!
But I still think that some ‘globals/constant’ (or what) should be implemented in MX2, like some ‘fingerprints’ for future uses (like the old AppTitle). I don’t think this will hurts neither MX2 or extern tools!
Cheers