I've recently been doing a lot of programming in decent languages(C++, lua) and my eyes have been opened. After coming back to DBPro to write a small example I noticed many limitations with the DBPro language that just make no sense and do nothing but impede development time and make using the language much harder for many users, especially beginners.
I will break this thread down into two sections, the first is what I deem to be issues and/or limitations of the language that are arbitrary, stupid or just shouldn't exist, the latter are issues that aren't required but would otherwise improve the language a lot, while keeping it within the spirits of BASIC.
Keep in mind, while some of these issues can be worked-around, or otherwise hacked in using various plugins people have written, I won't mention them because all of these features should be part of the core language, also, using work-arounds impedes learning and development time so it doesn't make much sense to suggest them over having the core language improved. Now for the first list:
1-1)
Lack of arrays in UDTs
This is an obvious one, it's been banged on about since day one. Allowing arrays in UDTs would make so much code far easier to implement and read, very often you see users asking about how to implement various features where using this(if implemented) would be the logical answer. You also often see new users who have followed tutorials on variables, arrays and the like, learn of UDTs they try and incorporate arrays into them and are hit by this arbitrary limitation and must learn some far more involved methods of working around this limitation or use very inefficient methods such as using a 2D array to work around this.
Example:
` Why doesn't this work??
type myType
dim inventory() as itemType
dim targets() as integer
endType
1-2)
The inability to return a UDT from a function
Yet another UDT based limitation, this shouldn't need a long explanation as the name says it all. There is no reason why you shouldn't be able to do this, every language I can think of that supports UDT/struct/class style objects has this ability and not allowing it is just arbitrary and detracts from development time.
Example:
type myType
var as integer
endType
function MakeSomething()
myVar as myType
myVar.var = 1337
` Totally doesn't work
endFunction myVar
1-3a)
Global variable declarations have to be 'executed' for initialization to happen
For example, the statement 'global var as integer = 1337' is only initialized(the value being set to 1337) once the statement itself is stepped-through. For purely literal assignments this limitation makes no sense, and the above statement isn't the same as declaring the variable and assigning whatever's after '=' to it. This limitation is particularly annoying when dealing with multiple source files, as you want to somewhat separate the files but you find you must create a special routine to initialize these variables as they are likely never stepped-through.
Example-Main.dba:
lives = maxLives
` It prints 0?? Not what you might expect
print lives
Example-MyInclude.dba:
global lives
global maxLives = 10
1-3b)
Global array declarations have to be 'executed' for initialization to happen
Before you say crazy stuff like the compiler has no idea what size to make the array as you can have multiple 'dim' statements, I am fully aware of this. The issue is that once you call 'dim something', the array itself is never created until 'dim' is run. Thus if you have multiple source files and you have 'dim something' at the top, the array isn't actually accessible until you step-through this line, or one like it. This again makes no sense and forces another initialization routine, by default arrays should have a size of -1(no indices) and only once you run a 'dim' with a different value or you add an index should this change. At present you get a completely unintuitive error that the requested index doesn't exist(it reports as having an 'array count()' of 0). Who knows, perhaps this is a bug, but it's still very similar to 3a and is still a limitation. Perhaps this could be fixed by implementing 'dim' and 'redim', 'dim' can only be called once for each array, that would at least make more sense.
Example-Main.dba:
` Insert an index
array insert at bottom someArray()
` Error!!!! the array isn't actually created yet, even though we'd expect it to begin as empty
someArray(0) = 5
Example-MyInclude.dba:
` Quite obvious we want an array here
dim someArray() as integer
1-4)
The inability to pass UDT data from an array to a function
This limitation makes even less sense, you can pass the contents of arrays that use any of the basic types to a function and you can assign the contents of any kind of array to a variable, but you can't pass a UDT array's contents to a function??? This limitation is again totally arbitrary and does nothing but impede development and confuse beginners.
Example:
type myType
var as integer
endType
dim array() as myType
` Stupid error
DoSomething( array(0) )
function DoSomething( in as myType )
endFunction
1-5)
The lack of a distinct 'elseif'/'else if' statement
While you can do separate 'else' and 'if' statements to work around this limitation, this requires you to close the new condition with an 'elseif' which can easily lead to a long line of 'endIf's which is very unintuitive to look at.
Example:
` Code that _should_ work
age as integer = 10
if age = 0
print "How are you playing this game??"
else if age < 5
print "You're too young to play this!"
else if age > 4 and age < 90
print "Have fun!"
else if age > 89
print "O_O"
endif
1-6)
Inability to do complex statements on 'exitFunction'/'endFunction'
The inability to do something like: 'endFunction something * 5' makes little sense in many cases, I could understand if DBPro was strict about data types as such a return might be ambiguous as to the type you wish to return, but in many cases it should be obvious by what variables you use in the statement, and any truely ambiguous statements should flag a warning. Thus this limitation makes no sense and just adds needless lines to your program.
Example:
` Code that _should_ work
function DegreeToRadian( in as float )
endFunction in * ( 3.141592654 / 180.0 )
1-7)
No function overloading
Function overloading is where you can declare multiple functions that bare the same name, but their arguments(variables passed to them) can either differ by data type, amount, or both. This feature is already present in the default command set and plugins, i.e. 'position camera X, Y, Z' or 'position camera ID, X, Y, Z' thus I see no reason why it isn't present in the language itself.
Example:
` Bad function overloading example
print Average( 1.0, 8.0 )
print Average( 5.0, 6.0, 7.0 )
` Note: this highlights 1-6
function Average( a as float, b as float )
temp as float
temp = ( a + b ) / 2
endFunction temp
function Average( a as float, b as float, c as float )
temp as float
temp = ( a + b + c ) / 3
endFunction temp
And now for a list of less-important features that should be added to make development time faster, but don't exist for some apparent reason:
2-1)
Lack of option explicit
Some users believe the ability to randomly use variables without declaring them beforehand is a feature, while this may be true, you should also have the ability to disable it as it can very quickly lead to issues that are very hard to debug.
Example:
` This currently works
someID as integer
someID = MakeEnemy()
` Notice the typo? Have fun debugging issues like this, or more complex ones
enemyList(somwID).name = "Zombie"
2-2)
Vectors and matrices aren't basic types
Both of these concepts are heavily used in game programming among other fields, but their implementation in DBPro is terrible to say the least. In addition to being basic types they should support the basic operators like addition, subtraction etc and generally behave somewhat like they do in HLSL.
Example:
myVector as vector3
myVector = object position( 1 )
position camera cameraID, myVector
myVector2 as vector4
myMatrix as matrix4
myMatrix = view matrix 4()
` Transform to view space for no reason
myVector2 = myMatrix * myVector
2-3)
No methods in UDTs
UDTs are nice and all, but they are still very limited when you wish to alter their contents. Methods are essentially functions that are bound to an object, a UDT in this case. Just like you can access a variable in a UDT using: 'myUDT.someVar = 5', with methods you would be able to have: 'myUDT.someMethod( 1337, "hello" )'. In addition to this, you would be able to access the local variables within the UDT as if they were global variables, this greatly allows you to encapsulate functionality and saves you from having to write a list of global functions that alter a UDT's contents.
While you can do similar to this using functions that take UDT input and... once implemented to the language can output them, one distinct difference is that because DBPro lacks references you can't(without using more hacks) have a function that outputs something like a boolean to indicate if the routine succeeded because the return type would be of your UDT type, unless it doesn't modify the contents. However there are enough instances where this would be an issue to warrant their implementation.
Example:
` How to use methods... ideally
myObject as myUDT
if myObject.Load( "Zombie.dbo" ) = 0
print "Failed to load zombie!"
endif
type myUDT
objectID as integer
path as string
` Declare a method
function Load( file as string )
worked as boolean = 0
if file exist( file )
worked = 1
objectID = whatever
load object objectID, file
path = file
endif
endFunction worked
endType
2-4)
No references
References are data types that act just like normal data types, except they merely reference a separate, existing variable. Think of them as 'instance object', except when you alter the instance, or reference in this case, you're altering the original. Thus any changes you make to a variable from a reference essentially propagate to the original and anything else referencing it. Such a feature is very important if you want to support multiple return values, for example: you could create 2 variables, pass them to a function that accepts 2 variables of their type that are references, and when the function modifies the input reference variables they will alter the ones you declared before calling the function, thus the function essentially just returned 2 types. There are other uses for this feature as well, this is just the tip of the iceberg.
Example:
` It really depends on what syntax is best, but I'll use 'reference' then the type here
function FixFilePath( in as reference string )
if file exist( in ) then exitFunction 1
if file exist( "Data/" + in )
in = "Data/" + in
exitFunction 1
endif
endFunction 0
There are probably many more issues I neglected to mention, but these are the ones that stood out that I could think of. If you have more then feel free to post, if you have an objection to any of the posts then feel free to post too, just make sure you read the whole point first.
Also remember that this list is mainly aimed at the issues/limitations of the core language, I could easily rant about the poor: compiler, editor, help files, default libraries etc, but this topic isn't the place for that(maybe a sequel?).
Lastly, I'm aware that these features are present in most other languages, such as C++ with GDK, but still, these features are incredibly important and implementing them wouldn't add complexity to the core language as you would still be able to write the same old code. I'm not asking for this language to be made into the next C++, C#, Java or whatever, but most of these suggested features are so obvious and have been implemented into so many languages you just have to wonder why they aren't in this one. DBPro is touted as being a simple language, ideal for people who want to get into game programming, but many of the limitations mentioned above just impede development time and confuse would-be developers, they may even turn them away if they're told this is the easy solution and find aspects of it make no sense, so hopefully some of these get implemented at some date.
Thanks for reading.
[edit] added one more, and some examples.