Language features

Community Forums/Monkey2 Talk/Language features

marksibly(Posted 2015) [#1]
***** Nested types, functions etc *****
class List<T>
   class Node
      field succ:Node
      field pred:Node
      field data:T
   end
   field head:Node
end

function fun1:void()
   class C
   end
   function fun2:void( c:C )
   end
   local c:=new C
   func2( c )
end



***** Generic functions with type inference *****

function Min<T>:T( x:T,y:T )
   if x<y return x else return y
end

function Main()
   print Min( 10,20 )
   print Min( "hello","there" )
end


***** Function values/types *****

function NegateValue:float( value:float )
   return -value
end

function ProcessValue:float( value:float,process:float( value:float ) )
   return process( value )
end

function Main:void()
   print ProcessValue( 10.0,NegateValue )
end


...use 'alias' for named delegates (not strongly typed like c# though), eg:

alias ValueProcessor:float(value:float)

function NegateValue:float( value:float )
   return -value
end

function ProcessValue:float( value:float,process:ValueProcessor )
   return process( value )
end

function Main:void()
   print ProcessValue( 10.0,NegateValue )
end


...function values can be member methods of dynamic objects, eg:

class ValueScaler
   field scale:float

   method new( scale:float )
      self.scale=scale
   end
   
   method ScaleValue:float( value:float )
      return value*scale
   end
end

function ProcessValue:float( value:float,process:float( value:float ) )
   return process( value )
end

function Main:void()
   local scaler:=new ValueScaler( 3 )
   print ProcessValue( 10.0,scaler.ScaleValue )
end


...use fields/properties for signals/slots, eg:

alias GizmoModifiedListener:void( Gizmo )

class Gizmo
   field OnModified:GizmoModifiedListener  'signal

   method Modify:void()
      OnModified self
   end
end

function GizmoModified:void( gizmo:Gizmo )   'slot
   print "Gizmo modified!"
end

function Main:void()
   local gizmo:=new Gizmo
   gizmo.OnModified=GizmoModified
   gizmo.Modify
end



***** Fix overloading/overriding *****

Monkey1 has several problem with function overloading/overriding, including:

* Derived classes cannot introduce a new overload for an overridden method.

* Overload resolution is too simple.

All will be fixed!


***** Null will be like bmx's Null *****

Null in monkey is currently an object. However, this means it's impossible for generic code to use 'default' values easily - several monkey libs depend on the language (only in non-strict!) returning default values from functions (and initializing globals to default values) to get around this - yuck!

Null will go back to being 'context dependant', eg: uninitialised var decls will effectively be equivalent to:

local t:SomeType=Null

***** Version to replace Strict *****

A version statement will be added to control how the parser works, eg:

version 1.0 'monkey1 non-strict
version 1.5 'monkey1 strict
version 2.0 'monkey2

Monkey2 mode will be pretty much the same as monkey1 'strict', but with as yet undetermined tweaks.


Samah(Posted 2015) [#2]
Annotations/metadata? Seriously, this has been easy since day one of reflection. You could do it in BlitzMax, why not Monkey?
Generic wildcards and bounding?
Coalesce operator like ?? in C#.


marksibly(Posted 2015) [#3]
Reflection in monkey1 is IMO horribly broken, largely due to the fact it has to target a bunch of languages so just generates 100001 'stub' class for each method/function/variable. I have not yet given any though to how reflection will work in monkey2, but it wont work the monkey1 way!

Generic constraints are possible, although I have always been dubious about how much benefit they add in exchange for adding such a lot of syntactic baggage to the language. At the very least, monkey2 will retain the option to specify 'any type' generic args the way monkey1/c++ do. Either way, you still get a compile time error if invalid parameter types are used.

Never seen the coalesce operator, but monkey2 will not support 'nullable' types. It may end up with a ternary operator though, so something like 'Local t:=p ? p : q' would be similar in the case of objects.


xlsior(Posted 2015) [#4]
I'd hope that 64-bit compatibility would be pretty high on the feature list as well -- pretty much all new PC's sold these days come with a 64-bit OS, and it's just a matter of time for 32-bit to die a slow death.


dawlane(Posted 2015) [#5]
Having the ability to generate 32/64 bit binaries without having to change project files would be nice. But what feature set of a c/c++ compiler would the translated code target? Not all GCC compilers on Linux support C++11 yet. It would also be nice if the translated could handle pkg-config being passed in LDFLAGS to GCC.


Danilo(Posted 2015) [#6]
marksibly wrote:
***** Nested types, functions etc *****
class List<T>
   class Node
      field succ:Node
      field pred:Node
      field data:T
   end
   field head:Node
end


You could differentiate between Public and Private classes (within classes):
Class List<T>
   Private Class Node
      field succ:Node
      field pred:Node
      field data:T
   End
   field head:Node
end

var x := new List<Int>.Node ' ERROR, Node is Private to List

Class List<T>
   Public Class Node
      field succ:Node
      field pred:Node
      field data:T
   End
   field head:Node
end

var x := new List<Int>.Node ' perfectly OK, Node is Public

If Public/Private are optional, you just have to decide what's the default access modifier.


Danilo(Posted 2015) [#7]
What about allowing multiple arguments for properties like the following example?
Function Main:Int()

    Local main:Window = New Window(800, 600)

    main.Position(100, 100)  ' works

    main.Position = 100, 100 ' doesn't work in MonkeyX
                             ' should automatically translate
                             ' to Position(100, 100) or setPosition(100, 100)

    main.Show()

    Return 0
End

Class Window
    Method New()
        ' create Window using default values
    End

    Method New(width:Int, height:Int, flags:Int = 0)
        ' create Window using default/random x,y
    End

    Method New(x:Int, y:Int, width:Int, height:Int, flags:Int = 0)
        ' create Window
    End
    
    Method Show(status:Bool = True)
    End
    
    Method Hide(status:Bool = True)
    End

    Method Position:Void(x:Int, y:Int) Property
        ' set Window position
    End
End

Google Go has the feature to return and receive multiple values:
package main

import "fmt"

func main() {
    x, y := Position()

    fmt.Println(x)
    fmt.Println(y)
}

func Position() (int, int) {
    return 800, 600
}


That could be implemented internally using hidden arguments (the generated C++ code would have 2 extra Parameters (by reference) to return 2 values).
x, y = main.Position

Go usage example:
f, err := os.Open(name)
if err != nil {
    return err
}
codeUsing(f)



MikeHart(Posted 2015) [#8]
Google Go has the feature to return and receive multiple values


Just like LUA.


ziggy(Posted 2015) [#9]
Delegates!!
Please, pair them with lambdas and the world will be perfect


Samah(Posted 2015) [#10]
@marksibly: Never seen the coalesce operator, but monkey2 will not support 'nullable' types.

So object references can't be null?
Local a:Object = Null
Local b:Object = Null
Local c:Object = New Object
Local d:Object = a ?? b ?? c
' a and b are null, therefore d = c


@MikeHart: Just like LUA.

Lua is a word, not an acronym.


Nobuyuki(Posted 2015) [#11]
Ternary operator would be great. Can we have VB.NET style Properties? Auto-implemented Properties would be nice, but I'd settle for a syntax that would be easy to autocomplete in an IDE even if it requires both Get/Set:

Class MyClass
  Private
    Field _count:Int
  Public
    Property Count:Int()
	Get  
	    Return _count
	End Get
	Set(value:Int)   'Optional block, if omitted, property becomes read-only
	    _count = value
	End Set
    End Property
End Class


This syntax also makes defining properties less ambiguous in the case that you should take Danilo's suggestion of allowing multiple setter arguments in a property...
Also, perhaps syntactic sugar could be used to shorten getter and setter blocks to one line, EG: "Get Returns _count"? I believe I've suggested reserving 'Returns' as a keyword before in a thread where someone hacked Lambda expressions into Monkey. It seems like a consistent way to tokenize an expression on the same line as a method definition...

Edit: I realize that reserving Get and Set might be a bad idea if you want to keep maximum backwards-compatibility. Here is an alternative syntax!


Class MyClass
  Private
    Field _count:Int
  Public
    Property Count:Int()
	Getter  
            Return _count
	Setter (value:Int) 
	    _count = value
    End Property
End Class


Edit 2: C# syntax assumes "value" as a default argument in a setter without needing to define it explicitly. I don't know enough about C# to know whether or not this makes it impossible to have multiple setters, or multi-argument setters, but it does make property syntax look far more consistent and terse.


Samah(Posted 2015) [#12]
This is a thread called "language features", not "feature syntax", so I'm wondering if we should focus more on the actual features themselves.
Perhaps we could compile a list of features other languages support that Monkey 1 does not. Pros and cons of adding the feature, any possible gotchas due to language translation, etc.
Otherwise, please rename this thread "property syntax".


Danilo(Posted 2015) [#13]
Language features:
What built-in simple/basic data types are planned? Signed and Unsigned types?
- Byte / UByte ? (8-bit)
- Word / UWord / Char ? (16-bit) - Char is 16bit with Unicode, would be 8bit with Ascii mode
- Long / ULong / DWord (32-bit)
- Quad / UQuad / LongLong / Int64 ? (64-bit)
- Int / Integer ? (Int32 if compiled 32bit, Int64 when compiled 64bit)
- Int8 / Int16 / Int32 / Int64 ?
- UInt8 / UInt16 / UInt32 / UInt64 ?
- Float / Single / Double ?
- String
- Bool

Is support for pointers planned?

Macros for text replacement?
Macro HiWord(_value_)
    Word( (( DWord(_value_) >> 16) & $FFFF) )
End Macro

Macro LoWord(_value_)
    Word( ( DWord(_value_) & $FFFF) )
End Macro


Easy Import of external .lib and external sources?
Import "User32.lib"
    Function MessageBox:Int32(hWnd:UInt, text:StringPtr, caption:StringPtr, type:UInt32)
    Function MsgBox:Int32(hWnd:UInt, text:StringPtr, caption:StringPtr, type:UInt32) As "_MessageBoxW@16"
End Import

Import "sourcefile.cpp"
    Class xyz
        Method New( x:String )
    End
End Import

Enumeration type?
Enum MONITOR_DPI_TYPE
    MDT_Effective_DPI  = 0
    MDT_Angular_DPI    = 1
    MDT_Raw_DPI        = 2
    MDT_Default        = MDT_Effective_DPI
End Enum

(used syntax is just examples, just would like to know what is planned feature-wise)


marksibly(Posted 2015) [#14]
Class MyClass
  Private
    Field _count:Int
  Public
    Property Count:Int()
	Getter  
            Return _count
	Setter (value:Int) 
	    _count = value
    End Property
End Class


Nice, although I still don't like the _count at class scope. Perhaps properties could have fields?

Class C
   Property Foo:Int
      Field foo:int   'can be accessed ONLY by members of this class via Foo.foo
      Getter
         Return foo
      Setter
         foo=value
   End
End


> What built-in simple/basic data types are planned?

At least the same as bmx: byte, short, int, long, float, double. All signed. byte and short are 8 and 16 bit, int/float and long/double are 'at least' 32 and 64 bit.

Characters will always look like ints to monkey code, but will be internally stored in at least 16 bit.

There will be some kind of pointer - bmx syntax seems good enough to me:

local t:int
local p:int ptr=varptr t
p[0]=100
print t


Pointer are of course as ugly as hell and wildly unsafe, but there is just no easy way to deal with a decent range of c++ libs without them. Ditto, the extra types above are mainly for dealing with libs.

One approach to making pointers 'safer' would be to add 'Unsafe' blocks that turn off GC, eg:

private

global p:intr ptr

function dangerous:void( t:int )
   p[0]=t
end

public

function safer:void( t:int )
   unsafe  'pause GC/whatever
      dangerous( t )
   end      'resume GC/whatever
end


Import "User32.lib"
    Function MessageBox:Int32(hWnd:UInt, text:StringPtr, caption:StringPtr, type:UInt32)
    Function MsgBox:Int32(hWnd:UInt, text:StringPtr, caption:StringPtr, type:UInt32) As "_MessageBoxW@16"
End Import


Nice!


marksibly(Posted 2015) [#15]
> Enumeration type?

Yes, definitely!

Syntax exactly how you described, plus optional 'extends'.


marksibly(Posted 2015) [#16]

Testing testing




Danilo(Posted 2015) [#17]
Thanks Mark, looks good so far. One more thing comes to mind when importing 3rd party libs: stdcall and cdecl
On Windows some libs use stdcall, others cdecl (with 32bit compilation).
With 64bit compilation there is only one calling convention: http://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention

Another language uses Import + ImportC to differentiate in 32bit mode, and Procedure + ProcedureC (required for callbacks,
and when writing DLLs).


marksibly(Posted 2015) [#18]
> stdcall and cdecl

This is less of an issue with monkey because the c++ compiler takes care of the low level stuff.

However, there is still an issue with callbacks like WndProc. I propose using an extern qualifier for these, eg:

Function MyWndProc:int( wparam:int, etc...) Extern "stdcall"   'can only be used with static functions.
    'dodgy code goes here...
End


I also reckon tagging an extern onto imports with your above style, eg:

Import "qtmonkey.lib" Extern "stdcall"
   ...decls...
End


Would be a shortcut for:

Import "qtmonkey.lib"
Extern "stdcall"
   ...decls...
End


I think it's still import to be able to use import on its own.


Danilo(Posted 2015) [#19]
Awesome and very powerful, thanks!


Pharmhaus(Posted 2015) [#20]

Generic constraints are possible, although I have always been dubious about how much benefit they add in exchange for adding such a lot of syntactic baggage to the language.


This is one of the things I would love to see because it makes programming so much more delight- and powerful.


Samah(Posted 2015) [#21]
@marksibly: Perhaps properties could have fields?

This is going along the path of Java enumerations, where each enum value is actually a full object with fields, constructors, and methods. This could actually be very useful if you use the property itself as a first class value.

In this example, we're making a static reference to the property, which instead returns a pointer to the property declaration itself. We can pass this declaration around as a value and execute the getter or setter passing in an instance of the object to which the property belongs.
Class Foo
	Property Bar:String
		Get
		Set
	End
End

Local a := New Foo
Local prop := Foo.Bar
prop[a] = "hello"
Print prop[a]
Print a.Bar ' same output as the previous line


At least the same as bmx: byte, short, int, long, float, double. All signed.

Given that this is primarily for C++ targets, it needs an unsigned type to make extern bindings easier.

Easy Import of external .lib and external sources?

I'd like to see inline externs so that we don't have to make a completely different source file for small snippets of native code. The target, etc. can be checked with preprocessor directives, and the externed code will only be included if the marked language matches. The braces are there so that "End" isn't parsed as C++ code.
Extern "C++" {
	cout << "hello";
} End


@marksibly: ...I have always been dubious about how much benefit they add...

Class Entity Abstract
	Method Shoot() Abstract
End
Class Enemy Extends Entity
	Method Shoot()
		Print "Enemy shoots"
	End
End
Class Tower Extends Entity
	Method Shoot()
		Print "Tower shoots"
	End
End

Function ShootAll(list:List<? Extends Entity>)
	For Local e := EachIn list
		e.Shoot() ' possible because we know that regardless of the wildcard, it at least extends Entity
	Next
End

Local enemies:List<Enemy> = New List<>() ' "diamond operator" type inference when instantiating generics
Local towers:List<Tower> = New List<>()

ShootAll(enemies) ' possible because Enemy extends Entity
ShootAll(towers) ' possible because Tower extends Entity



marksibly(Posted 2015) [#22]
> @marksibly: ...I have always been dubious about how much benefit they add...

My issue is with constraints is that this...

Function ShootAll<T>( list:List<T> )
   For Local e:=EachIn list
      e.Shoot()
   Next
End


...will also fail to compile if T does not extend Entity, only for different reasons. It is a little more unsafe, because if T doesn't extend Entity but still has a viable 'shoot' method it'll work, but that can also be useful. So adding constraints doesn't actually achieve all that much if the goal is to catch type errors at compile time.

That said, I agree that it makes for more 'correct' code so I have been thinking about a way to implement 'Where' constraints without having to add a whole 'sub language' to deal with it. The basic idea would be to treat Where as a kind of static_assert, and add an Extends operator to expressions, eg:

Class<T> C Where T Extends Entity
End


Here, the 'T Extends Entity' bit is really just a normal bool expression. This would be evaluated each time C<T> is instantiated (so it must be constant) and must evaluate to true, or a compile time error occurs.

'Extends' would be added as a normal operator, eg: you could use it inside templates like this:

If T Extends Blah 'probably more useful with a static_if
...dodgy special case code!
Endif

Where would also work with functions, so your above ShootAll code could be...

Function ShootAll<T>:Void( list:List<T> ) Where T Extends Entity     'T must extend Entity!
   ...
End


It also deals with '? extends C' vs'? super C' in quite a nice way, just swap the extends operands:

Function ShootAll<T>:Void( list:List<T> ) Where Entity Extends T     'T must be base class of entity!


It also allows you to express quite complex constraints, using And and Or etc, since where is a proper expression.


Samah(Posted 2015) [#23]
I suppose that could be a solution, however I hate the idea of bringing in yet another keyword.
Function ShootAll<T Extends Entity>(list:List<T>)

Seems much cleaner to me.


Shinkiro1(Posted 2015) [#24]
Just wanted to throw in an interesting link: https://www.youtube.com/watch?v=TH9VCN6UkyQ&list=PLmV5I2fxaiCKfxMBrNsU1kgKJXD3PkyxO

Jon Blow (creator of Braid) is working on a language specifically for games.
There might be some interesting ideas one can use from here.


Nobuyuki(Posted 2015) [#25]
@marksibly
Nice, although I still don't like the _count at class scope. Perhaps properties could have fields?


Sounds great. The example code and way to access private property members from within the class makes sense to me as well, though in Monkey I usually reserve using Properties for making field read-only, or processing a few class level vars at once in a setter, so I didn't want to recommend having fields in Property scope unless someone else thought it better. I'm sure if it's implemented in this fashion, I'll find more use scenarios for it. I'm sure it will also help assist some IDE autosense magic down the road, as well.

That said, I agree that it makes for more 'correct' code so I have been thinking about a way to implement 'Where' constraints without having to add a whole 'sub language' to deal with it. The basic idea would be to treat Where as a kind of static_assert, and add an Extends operator to expressions, eg:


+1, awesome idea and feels like it maintains a "BASIC spirit" in its syntax. If you were to implement this, would it just be used for generic constraints, or could it be used anywhere a static assertion would be usable?


dmaz(Posted 2015) [#26]
- most importantly.... operator overloading.
- anonymous objects, dynamic properties/typing/binding. (have the language encourage and make easy component type design)
(edit/removed:)
- closures, (I saw in another thread Mark said probably not, I hope he reconsiders as these are so nice for clean short code)


dawlane(Posted 2015) [#27]
As some of the post are indicating that may have syntax differences from the original Monkey. I would suggest the inclusion of a hash If/Then/Else/End directive.
#If MONKVER<2 Then
monkey1 code
#Else
monkey2 code
#End


dawlane(Posted 2015) [#28]
I think that it would also be nice if it was possible to include code file snippets in any location of code with a #include directive. There has been a few occasions where if have had to duplicate code in the same file.


arawkins(Posted 2015) [#29]
I have been playing with Haxe a bit lately and one of the features I've found really useful is string interpolation:

http://haxe.org/manual/lf-string-interpolation.html


With Haxe 3 it is no longer necessary to manually concatenate parts of a string due to the introduction of String Interpolation. Special identifiers, denoted by the dollar sign $ within a String enclosed by single-quote ' characters, are evaluated as if they were concatenated identifiers:

var x = 12;
// The value of x is 12
trace('The value of x is $x');





It's a small feature but it is very useful, just removes one of the many small speed bumps in prototyping for me. I would love it if you could add it to Monkey 2 :)


Nobuyuki(Posted 2015) [#30]
@arawkins
I actually prefer String.Format(str$, args$..) to inline string formatting. Maybe that's just because of my familiarity, but languages that allow expression evaluation in the middle of a string without a familiar syntax is gonna make strings look confusing to newbies and could be difficult to implement for several reasons. Due to the fact that strings are immutable in Monkey, many types of string operations (including concatenating) tend to obfuscate some of the the overhead necessary to performing these kinds of operations.

Adding Format() to the String's intrinsic functions would be helpful, and perhaps less difficult to implement efficiently since the coder has to explicitly call it. .NET's formatting is pretty powerful, but perhaps extremely over-engineered.

https://msdn.microsoft.com/en-us/library/system.string.format%28v=vs.110%29.aspx


AndroidAndy(Posted 2015) [#31]
@arawkins - string interpolation could be useful, maybe something closer to the way Swift does it?
// Swift: string interpolation
var x = 12
// The value of x is 12 
println( "The value of x is \(x)." )


Seems better to use the standard escape character to kick off the embedded variable notation. If Monkey2 supported the \ escape character it would be exactly the same as Swift. For current Monkey tilde escape character it would simply look like this:

' Monkey 2: possible string interpolation
Local x:Int = 12
' The value of x is 12 
Print "The value of x is ~(x)."


Seems like it would work and I would +1 for that and another +1 for Skn3's suggestion http://www.monkey-x.com/Community/posts.php?topic=9738 on escape characters...


arawkins(Posted 2015) [#32]
@Nobuyuki - Yes, I can appreciate how it would make strings look more confusing to someone new to the language. In fact I hit that exact problem when learning Haxe. Once I got used to it though it was just a really handy thing to use when I need to get some variable or another onto the screen (which I seem to need to do constantly when prototyping). I am actually completely clueless on the performance impact of doing it though. If it is something that would hurt performance then I could see how obfuscating that could make it annoying for someone trying to optimize their code.

@AndroidAndy - Sure, that makes sense to me. I also agree it would be nice to have the more common escape character, though I think I have mostly adjusted to the ~ at this point :)


AndroidAndy(Posted 2015) [#33]
@arawkins - for sure most have adjusted to the ~ escape character, but it didn't seem like Mark was necessarily against implementing that, it is a nuance to be sure but may benefit some who switch between different languages where \ for escape characters is a standard.

Now one of the issues I find with string interpolation is that you lose the formatting capability. I am going out on a limb hear to suggest a hybrid syntax that could provide a clean and simple (with less typing) syntax. Here is what that might look like:

' Monkey 2: possible string interpolation with proposed embedded formatting capabilities
Local energyFloat:Float = 120.1000002001

Print "The value of energyFloat is ~(energyFloat,%.02f)."          ' Prints The value of energyFloat is 120.10

Local energyDisplay:String = "Energy Level: ~(energyFloat,%.02f)"       ' The value of energyDisplay String is now "Energy Level: 120.10

' Of course if the format string is optional so the base works when the standard output format is ok
Print "The value of energyFloat is ~(energyFloat)."          ' Prints The value of energyFloat is 120.1000002001



Of course, the formatting codes are simply "C" style formatting codes so nothing to invent there just translating appropriately.


Samah(Posted 2015) [#34]
I would still prefer the oldschool tried-and-true printf-style system.
Print String.Format("energyFloat=%.3f", energyFloat)


Diddy already supports a simple version of this.


Sicilica(Posted 2015) [#35]
I'd like to propose checked exceptions (or the option to use checked exceptions), but I'm sure folks will disagree.


therevills(Posted 2015) [#36]
checked exceptions


Yeah those would be nice.


Samah(Posted 2015) [#37]
@Sicilica: I'd like to propose checked exceptions (or the option to use checked exceptions), but I'm sure folks will disagree.

+1


marksibly(Posted 2015) [#38]
I think you can all guess where I stand on checked exceptions - I am not fan.

I do have some experience with them. I remember writing a little browser waaaaay back in the early days of Java, and tearing my hair out trying to deal with them.

What I disliked most was how 'viral' they were. If you added some code to an existing function that called another function that threw a checked exception, it caused a huge 'ripple effect' through all your existing code (assuming you couldn't handle the exception, which is true 90% of the time) as you needed to add a 'throws' to your function, which affected all functions that called that function and so on.

You can avoid this by 'eating' the exception, but that's worse than letting it propagate to something that may be able to actually handle it. I think I ended up doing a lot of this anyway, because I got sick of rewriting every function prototype every time I wanted to use a new API.

Plus, since they're effectively part of the function signature, we'd need to add them to function types, eg:

Local func:void() throws SomeException 'have fun calling this!

There are other arguments for and again - there are some pretty good ones that I hadn't heard before here: http://stackoverflow.com/questions/613954/the-case-against-checked-exceptions

But, unless someone can erase that browser coding experience from my brain, checked exceptions wont be happening.


itto(Posted 2015) [#39]
-1 for checked exceptions.

While they are awesome to help crafting good software *when used correctly*, they become a nightmare when used inside an API or a third-part module in ways which only force you to "eat" them, hence rendering the whole thing completely useless. This is because sometimes exceptions are better dealt with at a higher infrastructure level, rather than in the method calling the exception-throwing code. This is why exceptions are awesome, because they bubble up and you can deal with them wherever you feel it's better to.

I would much rather see other programming features to aid in error-free software development, like design by contract (a bit extreme maybe), ranged parameters, named parameters, parameter checking in the language modules throwing IllegalArgumentException, mandatory return type from method/function signatures (like the "strict" keyword does, albeit without the silly mandatory return statement), etc.


Sicilica(Posted 2015) [#40]
I HATED checked exceptions when I was first learning Java. I hated a lot of things Java did, because I felt like the designers enforce their views on the programmers in a way that is not healthy. But, once I got used to it and wrote a couple bigger programs and then moved back to other languages, I felt really strongly that exceptions are completely useless if they aren't checked.

If we're going to have multiple return values, that's just as effective a way of defeating the same problem of error propagation. But the reality is, if you call a function and it doesn't complete (by throwing an exception, returning bad values, whatever), you HAVE to deal with it, whether by returning bad values yourself or providing a solution. You can't just ignore it.

I'm down for checked exceptions being an opt-in thing, because for learning or prototype development sometimes you want to just ignore the problem altogether. But I still prefer a checked exception to returning multiple values, because an exception is an object that can contain more information than an error code or whatever, unless you were going to return some instance of the exception class (or a similar superclass) anyway, which just means you have to worry about casting and things.

I will concede that in general the syntax for multiple checked exceptions becomes FAR too verbose, and if anyone has any ideas on how we can address that I'm glad to try something new.


Shinkiro1(Posted 2015) [#41]
- anonymous functions
- structs / objects on the stack
- named arguments (optional)
- multiple return values


Samah(Posted 2015) [#42]
A compromise to people disliking checked exceptions might be to have them as a compiler warning, but you can optionally (command line, config file, etc.) set it to be considered an error.


itto(Posted 2015) [#43]
My most desired language features would be (in order of importance):

- First-class functions (which if I understood correctly are already planned).
- Anonymous functions.
- Namespaces.
- Possibility to import only some functions/classes/whatever from a module.
- Class destructors.
- Variable number of arguments (i.e. C# params).

And something to remove various nuisances and increase expressiveness:

- Proper handling of interface inheritance (see here)
- Literal maps.
- Protected class members.
- Enums.
- Default get/set behavior for properties.
- Final keyword.


nullterm(Posted 2015) [#44]
- Struct on stack or as class/struct member (by value, not reference/pointer, great for Vec2f Vec3f Quaternion etc)
- Operator overloading (especially with Struct above)
- First class functions (global functions and member functions w/ "Self")
- Anonymous functions
- Namespace/Module
- Destructors of some sort (even if late, to catch OpenGL resource leaks)
- Swift/ObjC style class extension: ability to add functions to a class/struct from separate source files https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html

The last one is pretty cool. Imagine being able to add new functionality to mojo's Image class. I first learned how amazing this could be when I added a ton of helpful Python-style functions to Swift String / ObjC NSString. And it was great being able to add to the default string class's functionality, rather than deriving my own or using a tool kit class/module.




itto(Posted 2015) [#45]
- Swift/ObjC style class extension: ability to add functions to a class/struct from separate source files


Looks similar to messing around with prototypes in prototype-based languages such as JavaScript, am I right? That's a powerful feature indeed.


nullterm(Posted 2015) [#46]
@itto, slightly different implementation, but yeah the idea/goal is identical.


ziggy(Posted 2015) [#47]
That's the same as extension methods in .Net, isn't it?


nullterm(Posted 2015) [#48]
@ziggy very similar yeah


Samah(Posted 2015) [#49]
Very similar to categories in Objective-C, which is what nullterm was referring to.

@interface Image (MyCategory)
-(void)MyDrawX:(float)x
             y:(float)y
             z:(float)z
         angle:(float)angle;
@end

@implementation Image (MyCategory)
-(void)MyDrawX:(float)x
             y:(float)y
             z:(float)z
         angle:(float)angle
{
	// PushMatrix
	// Rotate angle
	// DrawImage self, x, y, angle
	// PopMatrix
}
@end

Image *alien;
alien = LoadImage( @"alien.png");
[alien MyDrawX:200 y:300 z:40 angle:45];



Danilo(Posted 2015) [#50]
nullterm's example looks more like a partial class in C#, without the keyword. :)

That means it's a compile-time thing and should be easy to do. It has the limitation that it's only possible with classes
where the source is known to the compiler. Not with external classes.
ObjC has also the ability to class_addMethod at runtime, which is probably not easy to do with C++ and some other languages.


Samah(Posted 2015) [#51]
@Danilo: Looks more like a partial class in C#, without the keyword. :)

Except you can't declare a partial class unless all parts are declared partial, which is not likely to be the case with precompiled assemblies.


Danilo(Posted 2015) [#52]
- Using the Objective-C runtime and method swizzling
Objective-C is a runtime-oriented language, which means that it has two possible places of making decisions about what will actually be executed:
it generally defers as many decisions as it can from compile and link time to runtime, which means that it does things dynamically whenever possible.



Samah(Posted 2015) [#53]
@Danilo: I quoted C#, not Objective-C, but awesome all the same.

I should have a go at getting this working with Monkey 1, just to prove the point that it can be done.
If we can do it with 1, we can do it with 2. :)


Danilo(Posted 2015) [#54]
@Samah:
What I'm trying to say is, if you can add new methods and fields anytime at runtime, you need to lookup such names at
runtime, instead using a fast direct method call (C++, ASM).
But that all depends how powerful it should be. Extending the vtable and setting a new method pointer at runtime is possible
to some extend. But the compiler must know at which vtable slot the method (obj.method()) is to be found. If any function can
simply add a new method/variable at runtime, this can get messy very quickly. So you would probably need to lookup at runtime
where method XYZ is to be found. If the added methods can also be overridden at runtime using a new signature (different parameters),
it gets more complicated.


Samah(Posted 2015) [#55]
@Danilo:
You could probably do it all in raw Monkey 2 anyway if you use a wrapper class. The only issue you might have is visibility, but you could probably work around that.

Edit: Example:
Class Image Extension
	Method MyDraw:Void(x:Float, y:Float, z:Float, angle:Float)
		' code using the usual "Self" reference
	End
End

Local img:Image = LoadImage("alien.png")
img.MyDraw(1, 2, 3, 4)

Translates to something like:
class Image_extension_wrapper {
public:
	static void MyDraw(Image *self, float x, float y, float z, float angle) {
		// code using the argument "self"
	}
};

Image *img = LoadImage("alien.png");
Image_extension_wrapper::MyDraw(img, 1, 2, 3, 4);


A bit messy, but wouldn't require any runtime hacks and could theoretically work with any target.


Danilo(Posted 2015) [#56]
So "Extension Image" should basically create a new class that inherits from class Image, and the compiler would
automatically use the new class, where Image is used in code? "new Image" becomes "new Image_Extension" under the hood?
That's a compile-time thing then.


Samah(Posted 2015) [#57]
@Danilo: That's a compile-time thing then.

Yep, which is what categories are in Objective-C. Using magic calls to add methods at runtime is something different, and maybe not within the scope of the language (though still quite useful).


Danilo(Posted 2015) [#58]
Samah wrote:
Using magic calls to add methods at runtime is something different, and maybe not within the scope of the language

I think so, too.


Michael Flad(Posted 2015) [#59]
When I last used ObjC it was just a dynamic dispatcher - easily doable in any language that supports any kind of function pointers and IIRC it wasn't possible to override methods as a requirement for optimizations.

It's been a few years (probably 2009) but I actually wondered why this should be such a great thing - it's something easily done as required by any coder and I wouldn't want to trade the faster ways to call methods in a either/or situation.

BOOPSI (I guess we do have some ex Amiga users here?) on the Amiga was a very similar concept.


Samah(Posted 2015) [#60]
@Danilo: So "Extension Image" should basically create a new class that inherits from class Image, and the compiler would
automatically use the new class, where Image is used in code? "new Image" becomes "new Image_Extension" under the hood?

Sorry, I misread this. No, this would be a standalone class. Otherwise you start getting into multiple inheritance mess. Still compile time though, as you said.


Shinkiro1(Posted 2015) [#61]
I am all for class extension obj-c style.

The only problem I see is that if these get evaluated at compile time, compile times might increase substantially.

edit: Oops, didn't read the previous posts.

edit2:
Can we have functions inside classes/functions/any scope? Then anonymous functions would only be syntactic sugar and not really needed.


itto(Posted 2015) [#62]
Can we have functions inside classes/functions/any scope? Then anonymous functions would only be syntactic sugar and not really needed.


But when talking about callbacks I can't really not think about anonymous functions. No matter how deep you can nest classes, I simply don't want to have to define a named method somewhere in a module to use as a callback (basically what I'm doing all the time now with Monkey using interfaces). Think about chaining many GUI animations to create a long and complex one, for example, the next one starting only when the previous one has finished. Or delegating GUI events. Or promises. The code gets tighter with blocks of code passed around.


marksibly(Posted 2015) [#63]
Class Image Extension
...


I quite like this, but as noted it would be a 'compile time' thing, eg:

* You wouldn't be able to override existing methods.

* Methods added this way couldn't be virtual (probably have to be 'final').

* You wouldn't be able to add fields.

But even with these limitations, I can still see it being useful.


marksibly(Posted 2015) [#64]
> I can't really not think about anonymous functions

While, these are doable they are problematic to 'parse' cleanly. As I posted earlier, monkey faces some of the same issues as python here:

http://www.artima.com/weblogs/viewpost.jsp?thread=147358

Similarly, I think any solution would be 'un-monkey-like'.

But local functions (closures) will be happening, so you'll be able to do:

Function Something:Int() ( x:Int )
   Function Bump:Int()
      Return x+1
   End
   Return Bump
End


A 'Return Function' statement is probably possible, as perhaps is a simple 'Return expression' style lambda, but probably not the whole 'function in the middle of an expression' enchilada.


Samah(Posted 2015) [#65]
@marksibly: But local functions (closures) will be happening...but probably not the whole 'function in the middle of an expression' enchilada.

To be honest I think this is good enough. In fact it's probably better, since you can reuse the closure rather than it only being defined in a single expression.

Regarding closures: Will we be able to reference variables as upvalues (eg. Lua) or do they need to be final (eg. Java)?

Lua:
local x = 3
local r = function()
	print(x) -- x doesn't need to be final
	x = 10 -- x can be assigned
end
r()
print(x) -- x has changed


Java:
final int x = 3;
Runnable r = new Runnable() {
	public void run() {
		System.out.println(x); // requires x to be final or it won't compile
		x = 10; // won't compile, because x is final
	}
}
r.run();
System.out.println(x); // x hasn't changed



nullterm(Posted 2015) [#66]
@marksibly "I quite like this, but as noted it would be a 'compile time' thing"

Works for me!

"* You wouldn't be able to override existing methods.
* Methods added this way couldn't be virtual (probably have to be 'final').
* You wouldn't be able to add fields.
But even with these limitations, I can still see it being useful."

Same ObjC/Swift limitations, all fine. The benefit is being able to augment existing class functionality in a subtle (but powerful) way. Not a full on replacement to Class Y Extends X.


marksibly(Posted 2015) [#67]
It's kind of an 'anti-interface'!


Samah(Posted 2015) [#68]
@marksibly: It's kind of an 'anti-interface'!

Like antimatter?
Interface Bar
End
Class Foo Implements Bar
End
Class Foo Extension Bar
End

UNIVERSE EXPLODES


Richard Betson(Posted 2015) [#69]
But local functions (closures) will be happening, so you'll be able to do:

Function Something:Int() ( x:Int )
Function Bump:Int()
Return x+1
End
Return Bump
End


+1 and I dig the Nested types mentioned earlier.


Danilo(Posted 2015) [#70]
marksibly wrote:
While, these are doable they are problematic to 'parse' cleanly. As I posted earlier, monkey faces some of the same issues as python here:

http://www.artima.com/weblogs/viewpost.jsp?thread=147358

Similarly, I think any solution would be 'un-monkey-like'.

In Monkey1 an [expression] can't contain a function declaration, only function calls.
So if an expression in Monkey2 starts with the keyword 'Function', it's a full
function declaration. And only that, no other additional operators that can be used with expressions.
The only difference is the missing function name.

I think it would usually look like this (for event handlers etc.):
obj.func = Function:Void()
               ' DoSomething()
           End

But could also look like this (depends on the user):
' function call with 2 anonymous functions as arguments
myFunction( Function:Int()
                DoSomething()
            End,
            Function:Int(x:Int, y:Int)
                DoSomething()
            End )

' With ; delimiter
myFunction( Function:Int(); DoSomething(); End,
            Function:Int(x:Int, y:Int); DoSomething(); End )

myFunction( Function:Int(); DoSomething(); End, Function:Int(x:Int, y:Int); DoSomething(); End )

obj.func = Function:Void(); DoSomething(); End

Do you have an example where it would be a parsing problem?

Personally I would prefer the first 2 versions, without using the ; delimiter,
but the delimiter shouldn't be a problem if somebody wants to use it. It already
works like this in Monkey1:
Function f3:Void(); Print("f3"); End

So the required change in the compiler would be:
[Expression] := [AnonymousFuncDeclaration] |
                [RealExpression]

Where RealExpression is the old behaviour. Everything down the line within [RealExpression]
can only refer to [RealExpression], not [Expression] (for example '(' [RealExpression] ')' etc.)


Samah(Posted 2015) [#71]
+1 to Danilo's examples/syntax. In terms of Monkey 2 syntax, that looks quite elegant.
I'm just wondering if the "parsing problem" is something to do with the translated code. Need more clarification from Mark.


Danilo(Posted 2015) [#72]
@Mark:
With your example:
Function Something:Int() ( x:Int )
   Function Bump:Int()
      Return x+1
   End
   Return Bump
End

There is a function returned.

My question is, how can Bump() later refer to 'x' (a parameter of parent function Something()),
after the function Something() has returned?
I think it would need to carry an activation record with it, so it can still use the parent args
after the parent function returned already.

Just playing little bit with the ideas.
Function Something:Int(s:String) ( x:Int )
   Function Bump:Int(s:String)
      Print(s)
      Return x+1
   End
   Return Bump
End

Function Something:Int(s:String) ( x:Int )
   Return Function:Int(s:String)
             Print(s)
             Return x+1
          End
End

func := Something(2)
x := func("Hello")

x := Something(4)("Hello")
Print(x)



nullterm(Posted 2015) [#73]
OH! Here's a biggie for me...
- Allocation free iterators - Having Struct's on the stack would help alot for this. I'm always cautious about using For EachIn because of potential gc hit allocating the iterator.


marksibly(Posted 2015) [#74]
My main concern is whether, in a language where newline has significance, this is really a good idea considering it's possible to achieve with a plain function decl. I don't want to confuse the hell out of people with 'what can I put on the end of a line'? etc.

I haven't thought much about the newline situation as yet, and while monkey currently has some hacks in it to allow expressions to span multiple lines (and monkey2 will have something similar - hopefully more elegant) in general I feel it goes against the 'basic' feel of the language, and don't know if I really want multiline expressions to become a fundamental part of the language.


itto(Posted 2015) [#75]
My main concern is whether, in a language where newline has significance, this is really a good idea considering it's possible to achieve with a plain function decl


True, when I thought about that I forgot for a moment Monkey doesn't have curly braces, so to say. However, other languages manage to have single line lambdas. Python is the most common example. Lua also has this possibility:


We can improve this in Lua with a utility function fn that creates an anonymous function from a shorter string representation. It might be used like this:


local y = map(fn("L1[P1]", translate), x)


fn takes as arguments a string representation of an expression defining the return value of the anonymous function to create and a list of local variables that are referred to as L1, L2, L3, ..., L9 in the expression. The arguments of the anonymous function are referred to with P1, P2, P3, ..., P9. fn can be defined in this way:


function fn(s, ...)
  local src = [[
    local L1, L2, L3, L4, L5, L6, L7, L8, L9 = ...
    return function(P1,P2,P3,P4,P5,P6,P7,P8,P9) return ]] .. s .. [[ end
  ]]
  return loadstring(src)(...)
end


Taken from here.

The keyword to create an anonymous function doesn't have to be the same as a normal function. It can be shorter, like f, fn, () => , whatever... When parsing, you see the anonymous function keyword and interpret the rest as normal code, stopping at a comma if we are parsing function parameters, or at a newline if we are somewhere else.

I know it may sound like it something not really needed for a language like Monkey, but I believe everyone agree on the fact that since Monkey has OOP features, generics, and other good features it's a much better language to code with than more BASIC-ish languages. They are extremely powerful. Even Java has now the ability for anonymous functions (Even though Java has curlies, the example could be translated literally to Monkey in a newline-matters style.)

What I'm trying to say is that it's not strictly necessary to implement multiline for such a feature. It would still be great to have support for them even if single-line only.


Danilo(Posted 2015) [#76]
I usually prefer clean and read-able style, and to be honest, some of the features (combined & chained) may already be complicated to use.
Not sure how attracting all those powerful features will be to beginners in M2.

Anyway, another question: How deep can those nested functions and classes be nested? Endlessly or only one depth?
To access the parent function arguments, the function variable must probably carry an activation record with it (see my last post),
and this gets even more complicated when it's nested multiple times.

Maybe this is a little bit over the top already, not sure.
Function Something:Int(s:String) ( x:Int )

    Function GetFunc:Int(s:String) ( y:Int )

        Function Bump:Int(s:String)
            Print(s)
            Return x*y ' parent/outer function parameters get accessed
                       ' by using an activation record that gets
                       ' carried with the function variable?
        End

        Return Bump
    End

    Return GetFunc(x*x)

End

func := Something(2)
x := func("Hello")
Print(x) ' 8

y := Something(4)("World")
Print(y) ' 64

- http://en.wikipedia.org/wiki/Nested_function
- http://en.wikipedia.org/wiki/Call_stack#ACTIVATION-RECORD


itto(Posted 2015) [#77]
myFunction( Function:Int()
                DoSomething()
            End,
            Function:Int(x:Int, y:Int)
                DoSomething()
            End )


This looks a little ugly and messy, there's the problem of the last closing parenthesis after the second function parameter, which is easy to miss and looks kinda out of place in a language like Monkey. Additionally, what if I wanted to have another parameter after the two functions, say, an integer? The last parameter would get hidden after potentially many lines of code. (It's a problem also in languages with curly braces, but since they are more expressive and dynamic this is usually not a problem.)

How about something like this?

function myFunction(x:int, y:int, f1:function, f2:function, makeLove:bool = false)
end

result = myFunction(10, 20, f1, f2, true) where ' <- postpone parameters declaration and starts a block (should be easier to parse?)
    f1 = function(foo:int, bar:int)
        ' function body
    end[function]
    f2 = function(param1:string, param2:string)
         ' function body
    end[function]
end[where]



itto(Posted 2015) [#78]
Incidentally, something like that could even be used in function definitions for parameter constraints, for example:

function myFuction(x:int, y:int, name:string) where x > 0, x < 100, name.Length() > 4
    ' Monkey automatically generates for us at compile time as the very first code in the function:
    if not (x > 0 and x < 100 and name.Length() > 4) then return ' or throw, or whatever
end



Danilo(Posted 2015) [#79]
@itto:
I don't think that's making it better, especially when 'where' means two different things. Also it's not easy to differentiate what
is a "postpone parameter declaration" and what is a variable. See following example where a+b are variables, c+d are the
postponed function declarations.
'
' event handler
'
obj.func = func1 where
    func1 = function:int(x:int, y:int, name:string) where x > 0, x < 100, name.Length() > 4
                ' function body
            end
end

'
' function call
'
result = myFunction(a, b, c, d, true) where
    c = function(foo:int, bar:int) where foo > 0 And foo < 11, bar <= 100
        ' function body
    end
    d = function(param1:string, param2:string) where param1 <> "", param2 <> ""
         ' function body
    end
end


Such function declaration lines can become really long:
function f:int(x:int, y:int, name:string) where x > 0, x < 100, name.Length() > 4
    ' function body
end

Splitting it at comma makes it look like this:
function f:int(x:int, y:int, name:string) where x > 0,
    x < 100,
    name.Length() > 4
    ' function body
end

By using a new keyword for it and include it into the function body (on separate lines), it would look like this:
function f1:int(x:int, y:int, name:string)
    Ensure x > 0; x < 100; name.Length() > 4
    ' function body
end

function f2:int(x:int, y:int, name:string)
    Ensure x > 0 And x < 100
    Ensure name.Length() > 4
    ' function body
end



itto(Posted 2015) [#80]
@Danilo you're right on the use of "where" for two different things, I didn't mean to use the same keyword, but to use a similar functionality (write something after the function signature).

As for distinguishing between function arguments and other arguments, they are defined in the function signature. If you look at my example, I'm calling the function myFunction which I declared before, with all parameter types specified. It's not an anonymous function, it's exactly like calling a normal function, you need to know which parameter types the function expects.

In the case of an anonymous function, you would still have to declare the parameters types the function expects anyway. Like:

x = function(a:int, b:int, c:function) ' anonymous function. Note that "c" is of function type, can't take something else
    return c(a, b) ' calls the callback passing the first two arguments, and returns the result 
end

' later on...
sum = x(2, 3, f) where
    f = function(a:int, b:int)
        return a + b
    end
end

product = x(10, 20, f) where
    f = function(a:int, b:int)
        return a * b
    end
end


EDIT

function f2:int(x:int, y:int, name:string)
    Ensure x > 0 And x < 100
    Ensure name.Length() > 4
    ' function body
end


Now that's something! :)
I love that


Shinkiro1(Posted 2015) [#81]
I think this is going a bit overboard.

A language should have a consistent syntax. Introducing new styles for the sake of implementing a feature is bad design.
Although I trust Mark on this one as he has always made sane decisions in that regard.

edit: This 'Ensure' syntax for functions would just complicate things. Just write that part in the body of the function. That way you can also express your intent more clearly.


marksibly(Posted 2015) [#82]
Yes! Just got this going...

function StartAt:int{int}( x:int )    'int{int} syntax will go!

	function IncrementBy:int( y:int )
		return x+y
	end
	
	return IncrementBy
end

function test:void( f:int{int} )
	print f( 3 )
end	

function main:void()

	local f1:=StartAt( 1 )
	local f2:=StartAt( 5 )
	
	test( f1 )
	test( f2 )
	
end


...based on: http://en.wikipedia.org/wiki/Closure_%28computer_programming%29

However, I no longer think 'function' is the right term for this. The function is actually 'evaluated' (ie: locals from outer scope are captured/copied) when code execution gets to 'function IncrementBy...' so it's actually closer to a lambda assigned to a var, eg:

Local IncrementBy:=Function:...etc...

I'll decide what to call everything when I get a bit more done, but I'm very happy with how this is turning out!


Anyway, another question: How deep can those nested functions and classes be nested? Endlessly or only one depth?


Nice weird case to consider. Captured locals should 'propagate' I guess. If you use a local declared two closure levels up, you'll end up using a captured version of the captured version used by the closure one level up (even if closure one level up never uses the local - it should still capture it).


Danilo(Posted 2015) [#83]
Nested functions usually can also call functions within their parent function and above, including the parent function itself for recursive stuff.

Simple example (should generally be valid with nested functions, if I didn't make a small mistake or typo):
function main_func:int( main_param:int )

    Local x := 4
    Local i := 5

    function a1:int( a1_param:int )

        Local x := 1

        function a2_1:int( a2_1_param:int )
            return a2_1_param - main_param
        end

        function a2_2:int( a2_2_param:int )
            Local x := 10
            return a2_2_param - b1(15) + x + a2_1(12)
        end

        return a2_1(a1_param + i) * a2_2(x*x)

    end

    function b1:int( b1_param:int )

        Local x := 2

        function b2_1:int( b2_1_param:int )
            return 15 * c1(b2_1_param)
        end

        function b2_2:int( b2_2_param:int )
            return 30 * c1(b2_2_param)
        end

        return i + x + b2_1(8) + b2_2(16) + c1(32)

    end

    function c1:int( c1_param:int )

        Local x := 3

        function c2_1:int( c2_1_param:int )
            return i + x + main_param + c2_1_param
        end

        function c2_2:int( c2_2_param:int )
            return i + x + main_param + c2_2_param
        end

        return c2_1(c1_param + x) - c2_2(c1_param + i)

    end

    return a1(15 + main_param)
end

value := main_func(42)
Print( value )



marksibly(Posted 2015) [#84]
The only problem I can see with that is forward referencing, b1 wont be able to see c1, as c1 doesn't exist yet when b1 is declared, ie: the above is effectively:

...
Local a1:=function(...)   'captures all *existing* locals, so can't capture b1, c1
...
Local b1:=function(...)   'can capture a1, but not c1.
...
Local c1:=function(...)   'can capture a1, b1
...



Danilo(Posted 2015) [#85]
Hmm, I thought that's not a problem, because forward referencing works automatically for functions already in Monkey1 -
without the need to declare forward references (like in some other languages).


marksibly(Posted 2015) [#86]
This is different though - these 'closures' are really just local variables, and locals in monkey (or any language) can't be forward referenced. Locals don't 'exist' until they're initialized, so a closure can't capture anything below its declaration.

Or: what if c1 captured a local declared somewhere between b1 and c1?

This is partly why I think the 'function' notation is misleading...


marksibly(Posted 2015) [#87]
It looks like there are languages that support forward referencing closures - as long as no vars are declared between the use and the def.

But I'm cool with the 'closures are local vars' approach for now, at least until I've had a bit more practical experience with this stuff. The above can certainly do anything I've done in JS/C++ to date.


Danilo(Posted 2015) [#88]
Shinkiro1 wrote:
edit: This 'Ensure' syntax for functions would just complicate things. Just write that part in the body of the function. That way you can also express your intent more clearly.

I think what itto had in mind is Design by Contract - at least it looked like it to me.

- (c2) - Constraint Programming
-- (c2) - Design By Contract
--- Design by Contract Programming in C++

- Microsoft Research: Code Contracts

In the above C++ example it's implemented using Macros that are used in Debug mode only,
and not used in final code.
The same could be done with Macros in M2, but AFAIK Macros are not planned (yet).

function f2:int(x:int, y:int, name:string)             ' Monkey1
    #if DEBUG
        if x > 0 And x < 100 and name.Length() > 4
            throw Exception
        end
    #endif
    ' function body
end

function f2:int(x:int, y:int, name:string)             ' using Macros (or Monkey1 functions)
    Require( x > 0 And x < 100 )
    Require( name.Length() > 4 )
    ' function body
end

I think this should be already possible with Monkey1 C++ target, using C++ macros.
You can import C++ macros as functions into Monkey1, like this MsgBox() example.
The C++ macro can just ignore it in release mode, so there is no function call overhead or empty function call in release mode.

If Monkey1 optimizes away empty functions and calls to empty void-functions, this can be done
with M1 functions already, without having any overhead in release mode.
Function Require:Void(x:Bool)
    #if DEBUG
        ' check x and throw or output message
    #endif
End



itto(Posted 2015) [#89]
@mark
Yes! Just got this going...

That's great! :)

However, I no longer think 'function' is the right term for this.

I didn't say it before cause I didn't want to put more things into the discussion, but I also think Function wouldn't be the right term to use. I would also consider something like Lambda to separate the two meanings. Moreover, I'm concerned about the type to use for variables. If we separate the two keywords but use a single one for function arguments/variables, it doesn't seem right to me. Perhaps a single keyword which encompasses them all? For example, in Perl we have coderefs (code references), which comprises functions (subroutines actually), methods, literal code blocks and evals.

@Danilo I think what itto had in mind is Design by Contract - at least it looked like it to me.

Yep. Design by contract is the most powerful form of defensive programming I've encountered until now in OOP languages. You not only have to declare preconditions and postconditions in the contract, but also class invariants (and this last point is the reason why it's so hard to implement DbC in languages which don't have it by default, you need to design the language upfront to implement it.)

In functional languages instead, Haskell-like pattern matching is the way to go:

f x y  |  y>z           =  ... execute only if y > z
       |  y==z          =  ... execute only if y equals z
       |  y<z           =  ... execute only if y < z
     where z = x*x


Now, while Design by Contract is perhaps too extreme, defensive programming in general is regarded as a good methodology to create good software. This includes assertions to validate function parameters for example. Which, like Danilo wrote, are usually implemented with macros in languages which permit so. Having to use a real function for that means that every time a function gets called, one or more other functions have to be called for parameter checking, which is not so nice imho (not least because they mess up the call chain and debugging gets harder).

In my Monkey code right now I use them like this:

function myComplexAlgorithm:int(x:int, y:int, z:int)
    #if ARGUMENTS_VALIDATION
        if x < 0 then throw
        if y > 10 ...
        ...
    #end
end


Pretty fugly I must say, but hey.

Finally,

A language should have a consistent syntax. Introducing new styles for the sake of implementing a feature is bad design.


I agree with you to a certain extent. I think if a powerful feature is within reach without having to turn upside down the entire language, then why not? Sometimes a slightly change in the main program syntax is welcomed if the feature matters enough. Below are two examples.

Python literal dictionaries
diceRoll = { (1,1): "snake eyes", (6,6): "box cars" }
myBoat = { "NAME":"KaDiMa", "LOA":18, 
 "SAILS":["main","jib","spinnaker"] }


Ruby lambdas
def generic_return(code)
  one, two    = 1, 2
  three, four = code.call(one, two)
  return "Give me a #{three} and a #{four}"
end

puts generic_return(lambda { |x, y| return x + 2, y + 2 })


Yes, Python and Ruby both use curly braces :)


Nobuyuki(Posted 2015) [#90]
Using "Where" for assertions was suggested before, and I think it's a fine idea, for both declarations (maybe requiring static assertion for speed purposes?) and also anywhere within a procedure (like Assert in java). However, for anonymous functions I prefer one of the many other keyword suggestions made for opening such a code block to "Where". My original suggestion was "Returns". Danilo suggested in another thread using "Do" for separating statements from expressions on the same line. It's annoying to think of a keyword that entails two similar use cases while excluding ambiguity with an unrelated use case. Perhaps "Returning" reduces most ambiguity of the context of where this keyword could be used?

Local x = Lambda (a:int, b:int, c:Func) Returning c(a, b) 



Danilo(Posted 2015) [#91]
@Nobuyuki:
Local x = Lambda (a:int, b:int, c:Func) Returning c(a, b)


Wouldn't that already be possible by using ordinary functions and function variables? (and without introducing new keywords/syntax)
Alias CalcFunc:int(a:int, b:int)
Function calc:int(a:int, b:int, c:CalcFunc) Inline; return c(a, b); End


' later on...
Local sum := calc(2, 3, Function:int(a:int, b:int)
                          return a + b
                        End )

Local product := calc(10, 20, Function:int(a:int, b:int)
                                return a * b
                              End )

' one-liner, if functions are small
Local   sum   := calc( 2,  3, Function:int(a:int, b:int); return a + b; End )
Local product := calc(10, 20, Function:int(a:int, b:int); return a * b; End )



itto(Posted 2015) [#92]
@Danilo the problem is that when you write a one line lambda, you don't want the cumbersome syntax to be in the way. Having to write that end keyword shouldn't be necessary and creates a mess. That's why also Ruby drops its standard blocky syntax in favor of simple braces when creating lambdas. Imho only a keyword should be necessary, like in a If ... Then one liner.


Danilo(Posted 2015) [#93]
Alias CalcFunc:int(a:int, b:int)
Function calc:int(a:int, b:int, c:CalcFunc) Inline; return c(a, b); End

' one-liner, if functions are small
Local   sum   := calc( 2,  3, lambda<CalcFunc>( return a + b ) )
Local product := calc(10, 20, lambda<CalcFunc>( return a * b ) )

' or
Local   sum   := calc( 2,  3, lambda:CalcFunc< return a + b > )
Local product := calc(10, 20, lambda:CalcFunc< return a * b > )

' or
Local   sum   := calc( 2,  3, lambda:CalcFunc return a + b )
Local product := calc(10, 20, lambda:CalcFunc return a * b )

' or
Local   sum   := calc( 2,  3, CalcFunc< return a + b > )
Local product := calc(10, 20, CalcFunc< return a * b > )

' or
Local   sum   := calc( 2,  3, CalcFunc( return a + b ) )
Local product := calc(10, 20, CalcFunc( return a * b ) )

' or
Local   sum   := calc( 2,  3, lambda:CalcFunc( return a + b ) )
Local product := calc(10, 20, lambda:CalcFunc( return a * b ) )

' or
Local   sum   := calc( 2,  3, lambda:int(a:int, b:int)( return a + b ) )
Local product := calc(10, 20, lambda:int(a:int, b:int)( return a * b ) )

I'm tired, gn8 ;)


itto(Posted 2015) [#94]
My take (I think I may have messed up something with the generics but nevermind, focus on the lambdas ;)

class Collections<T>
    function Filter:ICollection<T>(collection:ICollection<T>, f:bool{T}, stopOnFalse:bool = false)
        local filteredCollection:= new Collection<T>
        for local e:= eachin collection
            if f(e)
                filteredCollection.Add(e)
            else
                if stopOnFalse then exit
            end
        next
        return filteredCollection
    end
end

' class MyList implements ICollection
local list:MyList<SomeItem> = getItemListSomewhere()

' parameters inside delimiters, function body after keyword
list = Collections<SomeItem>.Filter(list, lambda:bool (i:SomeItem) returning i.GetPrice() > 100, false)
list = Collections<SomeItem>.Filter(list, lambda:bool {i:SomeItem} returning i.GetPrice() > 100, false)
list = Collections<SomeItem>.Filter(list, lambda:bool |i:SomeItem| returning i.GetPrice() > 100, true)

' parameters separated from lambda keyword by whitespace and from function body by symbol, 
list = Collections<SomeItem>.Filter(list, lambda:bool i:SomeItem -> return i.GetPrice() > 100)
list = Collections<SomeItem>.Filter(list, lambda:bool i:SomeItem = return i.GetPrice() > 100)

' tidier (usually "=>" implies "returning the following"; see C#, Dart, ...)
list = Collections<SomeItem>.Filter(list, fn:bool {i:SomeItem} => {i.GetPrice() > 100})
list = Collections<SomeItem>.Filter(list, fn:bool {i:SomeItem} => i.GetPrice() > 100)
list = Collections<SomeItem>.Filter(list, fn:bool {i:SomeItem} { return i.GetPrice() > 100 })

' parameter types inferred from Collection.Filter signature? Seems logic since their types couldn't possibly differ anyway
' We are passing a parameter to a function, which has to be type-checked against its signature
list = Collections<SomeItem>.Filter(list, fn {i} => i.GetPrice() > 100, true)



Nobuyuki(Posted 2015) [#95]
I tried to adapt itto's callback example sometime at 5 in the morning but wasn't sure if my changes made sense, so I truncated the majority of the examples in my previous code post. But essentially, the Returning syntax should also remove some ambiguity for the lexer when book-ending lambda-style code blocks, whether or not they're on multiple lines. The issue is making sure the syntax keeps the code blocks obvious and readable in a BASIC-like way. That means 1. no symbol soup, and 2. no keywords which put too much of a strain on the English language (IE: No symbol soup put through a RegEx to superficially resemble BASIC).

I'm okay with an operator that means the same thing as "Returning" as long as it has an established usage pattern outside of the voodoo world of C++ 1x. => fits the bill somewhat although for most of these languages, anonymous and higher-order functions were bolt-ons, not something considered when the language was first designed. I believe Ruby has some of the easiest to understand syntax for this, but it's a dynamic-typed language SO that may hide some of the nastier-looking stuff. (Also, Ruby isn't afraid of repurposing symbols to fit their paradigm, something that Monkey is only partially more constrained by)...


I'm still groggy so sorry for not coming up with an updated example :)


Danilo(Posted 2015) [#96]
It is interesting to take a look at how VB.NET does it, as it uses the 'function' keyword like Monkey1. It allows single and multiline function blocks.
- Lambda Expressions (Visual Basic)
- Basic Instincts: Lambda Expressions
- How to: Create a Lambda Expression (Visual Basic)
- How to: Pass Procedures to Another Procedure in Visual Basic

Those VB.NET examples could nicely be translated into Monkey style, IMO.


Nobuyuki(Posted 2015) [#97]
@Danilo

I first learned how to use anonymous functions with VB.NET, and that's one area where the BASIC constraints to the syntax really start to hurt, and where lambdas really start to feel bolted-on. Maybe it's just because the syntax assumes the type from the output? (VB.NET is normally explicit by default.) I'm hoping we can make Monkey syntax clearer than some of the weird-looking syntax there (particularly the way the compiler has to analyze the loads of parenthesis) without resorting to a bunch of symbols to do it. Semantically, some of VB's choices make sense to reduce ambiguity to VB people; other things maybe we can do better. If Mark says that the types of closures in Monkey2 aren't exactly 'true' higher order functions (or at least the same as functions in a technical sense -- the distinction is starting to go over my head), calling it something different could be a good idea, and having block keywords for them like Lambda..Returns can serve to do that.

Also, if you start to nest multiline anonymous functions, VB.NET's syntax starts to get a bit hairy, and the whole "End )" thing starts to crop up again. This type of code block has syntax that is clearly different from other code blocks in VB, but aren't.....exactly consistent. Oh boy, I think I'm starting to understand why Guido has a problem with this stuff...


dmaz(Posted 2015) [#98]
Yes! Just got this going...
Awesome!! even with the slight limitation (I can't see how it will effect my style) this is so good to see! can't wait. js gets by with forwarding referencing by hoisting all vars right... don't do that :) strict block scope is far more clean.

As for the parameter constraints, what's wrong with adopting BMX's debug only Assert statement in the function body?

for the lambdas, I don't get why you guys want symbol containers or a keyword... what's wrong with
Local f:=Function<CalcFunc>( a:Int, b:Int ); Return a+b; End	' if ; are required if on same line
'or
Local f:=Function<CalcFunc>( a:Int, b:Int ) Return a+b End	' monkey style
'or
Local f:=Function<CalcFunc>( a:Int, b:Int )			
	Return a+b
End
(the fact that it's an assignment should be all that's needed, no?)

since closures have been nailed... I'll add something else to my previous list :)
- assignments returning a value. (so we can declare in control statements and get chained assignments as a side effect)
I've missed that for a long time.


dmaz(Posted 2015) [#99]
oh, and I want to re-push operator overloading.


Nobuyuki(Posted 2015) [#100]
dmaz: for simple lambdas this looks fine but it gets hairy looking really fast; parsing it requires understanding the context of the declaration to open a code block for a lambda (and so now you can theoretically get return statements anywhere and the compiler has to deal with this and figure out where the lambda definition for it is), and it doesn't follow the usual conventions for code blocks in Monkey or indeed most BASIC dialects. Lambdas should probably have a code block syntax that resembles other flow-changing blocks like If..Then which makes it clear what's being used and where. This is of course a matter of opinion.....


dmaz(Posted 2015) [#101]
Lambdas should probably have a code block syntax that resembles other flow-changing blocks like If..Then which makes it clear what's being used and where.
sure, I see where you're coming from but in bmx and monkey flow-changing blocks don't have require parens or other keywords. unless I missed something, that seems to still be the case with monkey2...? I can see lambda as a function param being a problem but not allowing that shouldn't pose issues(?)

I have written some lexers but never a compiler so I don't understand why "getting return statements anywhere" would be an problem?


Samah(Posted 2015) [#102]
@marksibly: ...in a language where newline has significance...

And this is my biggest gripe with basic-ish languages in general. The fact that (sometimes) semicolons are not even mandatory for multiple statements on a single line is beyond me.
a = 1 b = 2 c = 3

If this compiles, there's something wrong with the grammar design. It makes code harder to read and trickier to parse.

@marksibly: ...and don't know if I really want multiline expressions to become a fundamental part of the language.

Agreed, if newlines are essentially ending a statement like in most basic languages.

@Danilo: Not sure how attracting all those powerful features will be to beginners in M2.

Planning advanced features of a language should not be hindered by how friendly it is to "beginners". Beginners simply won't use them.

Shinkiro1: A language should have a consistent syntax. Introducing new styles for the sake of implementing a feature is bad design.

Agreed.

@marksibly: The function is actually 'evaluated' (ie: locals from outer scope are captured/copied)

So like a weird cross between my Java and Lua examples. I think it's a bad idea to be able to reference an outer scope variable by name if assigning a value to it only changes the implicit local copy. This is why Java requires them to be declared final, to avoid this kind of confusion.
If you're going to copy the value in, you should make the copy implicitly final/readonly, and fail compilation if they try to assign to it.


ziggy(Posted 2015) [#103]
So like a weird cross between my Java and Lua examples. I think it's a bad idea to be able to reference an outer scope variable by name if assigning a value to it only changes the implicit local copy. This is why Java requires them to be declared final, to avoid this kind of confusion.
If you're going to copy the value in, you should make the copy implicitly final/readonly, and fail compilation if they try to assign to it.
I like changing outer variables from inside a nested lambda. It can be handy sometimes


Samah(Posted 2015) [#104]
@ziggy: I like changing outer variables from inside a nested lambda. It can be handy sometimes

Agreed, however I was pointing out two possible solutions:
1) Allow the closure to have full read/write access to the variables in the outer scope, or
2) Give the closure read-only copies.

The problem with 1) is that the variables will leave scope as soon as the outer function returns. There is no reason for a closure to write to a variable in an enclosing scope unless it will be read after the closure/lambda has been executed, before those variables leave scope.


Danilo(Posted 2015) [#105]
Nobuyuki wrote:
Maybe it's just because the syntax assumes the type from the output? (VB.NET is normally explicit by default.)

Well, that's all explained in the article I mentioned:
- Basic Instincts: Lambda Expressions

The article even explains how closures are created in VB.NET to capture the free variables of the parent function.
I think the closure could also contain all the other sub-functions within the parent function, so that could help with
the forward-referencing problem Mark was talking about yesterday.

Local mul := Function(x,y) x * y               ' Type inference: compiler decides return type from Input types
                                               ' Input could be floats, integer, bytes, matrices


Local mul := Function:int(x:int, y:int) x * y  ' this would explicitely allow int only

Local x := mul(5,11)                           ' if used with  int , typeOf(x) will be int
                                               ' if used with float, typeof(x) will be float
Print(x)

And:
Function(x,y) x * y

is a shortcut for:
Function(x,y) return x * y
' or
Function(x,y) return [expression]

which is a shortcut for:
Function(x,y)
    return [expression]
End

The difference between single-line and multi-line function arguments is:
Local f1 := Function:type(args)<end-of-line>  ' EOL means it's a full function with body
                ' function body
            End

Local f2 := Function:type(args) return [expression]
' or
Local f2 := Function:type(args) [expression]  ' omiting 'return'

VB.NET allows only an expression for single-line function arguments.
MX2 could enhance that by using a [statement-list], which is [statement]'s separated by semicolon (that's Monkey style already),
and omiting 'return' wouldn't be allowed then (except for lamdas that return void, of course).


itto(Posted 2015) [#106]
@dimaz In your examples:

Local f:=Function<CalcFunc>( a:Int, b:Int ); Return a+b; End    ' if ; are required if on same line
'or
Local f:=Function<CalcFunc>( a:Int, b:Int ) Return a+b End  ' monkey style
'or
Local f:=Function<CalcFunc>( a:Int, b:Int )         
    Return a+b
End


You are assigning a reference to an anonymous function to a variable. But you still have to declare the variable. That's not different from simply declaring a function (since Mark already showed in a previous post that there's the possibility to have nested functions).

Function f:function<CalcFunc>( a:Int, b:Int )
    Return a+b
End


If you have to pass around an anonymous function reference stored in a variable, you could very well declare it as a function in the first place. The point with anonymous functions is to be able to pass them to other functions as parameters on the fly, without having to declare anything beforehand, mostly for throw-away code (or code not reused anywhere).

@Danilo thanks for the article, I didn't even know VB supported lambdas. The part relative to type inference is exactly what I was referring about in my last example. That makes everything so much cleaner.

Anyway, obviously the BASIC syntax is not well suited for this, but if even VB gives you the option to use them with its clunky syntax... I see it as a living proof that this should be welcomed also in Monkey :)

This VB code looks neat anyway, but I'd prefer to see at least a symbol separating the lambda body from the head.
ProcessList(list, Function(person As Person) person.age > 50)


Of all the code I've seen until now in this thread, for function parameters I still prefer the idea of postponing the function code. It stays blocky (BASIC-ish), structured, and no parentheses mess.

interface GUIElements
    method Each:GUIElements(f:void{GUIElement}) ' processes each element in the collection, returns self for chaining
    method Filter:GUIElements(f:bool{GUIElement}) ' filter out unwanted elements from the collection, returns self
end

' get a collection consisting of all buttons in the GUI and disable them
local disabledButtons:= GUI.GetElements("button").Each(f) where   ' given? whatever...
    f = function(e)     ' <- types inferred
        e.Disable()
    end
end


Going more hardcore.

local disabledButtons:= GUI.GetElements("button").Each(f) where
    f = function(e) => e.Disable()
end


Going full power. Each returns the same element for chaining, "where" block considers all methods parameters (dunno, maybe it's technically not feasible.)

local disabledButtons:= GUI.GetElements("button").Filter(onlyVisible).Each(disable).Each(animate) where
    onlyVisible = function(e) => e.IsVisible()
    disable = function(e) => e.Disable()
    animate = function(e) => e.Animate("x", GetScreenWidth() + e.GetWidth(), 500) ' every button goes offscreen in 500 ms

    ' alternate syntax for word lovers
    ' disable is function(e) returning e.Disable()
end


Commodity single-line syntax for short ones.

local disabledButtons:= GUI.GetElements("button").Each(function(e) => e.Disable())



Danilo(Posted 2015) [#107]
I think
obj.func = Function(x) [statement-list]
obj.func = Function(x) [statement]
obj.func = Function(x)
             [statements]
           End

should be enough for MX2.

person.age > 50

isn't a [statement] but an [expression], so MX would require a 'return' statement for anonymous functions
that return something.
ProcessList(list, Function:bool(person:Person) return person.age > 50)

ProcessList(list, Function:bool(person:Person) Debug(person.ToString()); return person.age > 50)

ProcessList(list, Function:bool(person:Person)
                      Debug(person.ToString())
                      return person.age > 50
                  End )

Function processPerson:bool(person:Person)
    Debug(person.ToString())
    return person.age > 50
End

ProcessList(list, processPerson)



itto(Posted 2015) [#108]
@Danilo
ProcessList(list, Function(person As Person) person.age > 50)


this was a code taken directly from the VB article you linked, so it's VB code :) I wanted to point out it looks neat considering it's VB code.


Danilo(Posted 2015) [#109]
@itto:
Just wanted to say that using [statement] and [statement-list] is more powerful than using [expression] (like VB.NET),
so you would need the 'return' for non-void functions anyway. ;)


itto(Posted 2015) [#110]
@Danilo oh, got it! ^^


PixelPaladin(Posted 2015) [#111]
Implementing functions as classes could also solve many problems. Here is an example for functions with optional parameters:

Function A:Int(x:Int, y:Int = 3)
	Return x+y
End

Function B:Int(x:Int, y:Int, f:Function<Int(Int,Int)>)
	Return f(x, y)
End

Function C:Int(x:Int, f:Function<Int(Int)>)
	Return f(x)
End

Function Main:Void()
	Print("B(1,2,a) = " + B(1,2,A))
	Print("C(1,a) = " + C(1,A))
End


This could be translated to:

' Interface for functions of type Void with 0 parameters
Interface Function_0_Void
	Method Invoke:Void()
End

' Interface for functions with return type and 1 parameter
Interface Function_1_Ret<ReturnType, ParamType1>
	Method Invoke:ReturnType(ParamType1)
End

' Interface for functions with return type and 2 parameters
Interface Function_2_Ret<ReturnType, ParamType1, ParamType2>
	Method Invoke:ReturnType(ParamType1, ParamType2)
End

' Interface for functions with return type and 3 parameters
Interface Function_3_Ret<ReturnType, ParamType1, ParamType2, ParamType3>
	Method Invoke:ReturnType(ParamType1, ParamType2, ParamType3)
End

' Class for function A
Class Function_A Implements Function_1_Ret<Int,Int,Int>, Function_2_Ret<Int,Int,Int>
	Method Invoke:Int(x:Int, y:Int = 3)
		Return x+y
	End
End

' Function A
Global A := New Function_A

' Class for function B
Class Function_B Implements Function_3_Ret<Int,Int,Int,Function_2_Ret<Int(Int,Int)>>
	Method Invoke:Int(x:Int, y:Int, f:Function_2_Ret<Int(Int,Int)>)
		Return f(x, y)
	End
End

' Function B
Global B := New Function_B

' Class for function C
Class Function_C Implements Function_2_Ret<Int,Int,Function_1_Ret<Int(Int)>>
	Method Invoke:Int(x:Int, f:Function_1_Ret<Int(Int)>)
		Return f(x)
	End
End

' Function C
Global C := New Function_C

' Class for function Main
Class Function_Main Implements Function_0_Void
	Method Invoke:Void()
		Print("B(1,2,a) = " + B(1,2,A))
		Print("C(1,a) = " + C(1,A))
	End
End


This example also avoids the use of curly brackets.

It should be also possible to access values and functions of the parent function by handing over these variables to the sub function (similar to what is done in c++ by capturing values: see here).
Here an example:

Function CreateAdder:Function<Int(Int)>(x:Int)
	Function F:Int(y:Int)[x]
		Return x+y
	End
	Return F
End


This could be translated to:

' Interface for functions with return type and 1 parameter
Interface Function_1_Ret<ReturnType, ParamType1>
	Method Invoke:ReturnType(ParamType1)
End

' Class for function CreateAdder
Class Function_CreateAdder Implements Function_1_Ret<Function_1_Ret<Int,Int>,Int>
	Method Invoke:Function_1_Ret<Int,Int>(x:Int)
		Local F := New Function_CreateAdder_F(x)
		Return F
	End
End

' Class for function CreateAdder.F
Class Function_CreateAdder_F Implements Function_1_Ret<Int,Int>
	Field x:Int
	
	Method New(x:Int)
		Self.x = x
	End
	
	Method Invoke:Int(y:Int)
		Return x+y
	End
End

' Function CreateAdder
Global CreateAdder := New Function_CreateAdder


Using pointers it is also possible to capture variables by reference.

The only problem with the examples above should be a performance drop down.

edit:
Maybe it would be better to differentiate between functions and lambda functions:

Function CreateAdder:Lambda<Int(Int)>(x:Int)
	Local F := Lambda:Int(y:Int)[x]
		Return x+y
	End
End


In this example only the lambda function would be converted into a class while the CreateAdder function would still be a 'normal' monkey function. With this the performance should be reasonable in the end.


ziggy(Posted 2015) [#112]
person.age > 50
isn't a [statement] but an [expression], so MX would require a 'return' statement for anonymous functions
that return something.

Only when expressed in a single-line mode (which I find very nice), we could consider the expression itself the return data and datatype, and use data type inference here, so we can keep it minimal, typesafe, and as tiny and readable as possible. I find it to be very expressive:
Local isPossitive := Function(value1:Int) value1>=0

It should be very obvious that "isPossitive" is a pointer to a function that returns a boolean indicated if a value is greater than 0.

Much better than:
Local isPositive:Bool(param1:Int) = Function(value1:Int) Returns value1 >= 0

Too much verbosity with no tangible benefit


Nobuyuki(Posted 2015) [#113]
Itto said:
Anyway, obviously the BASIC syntax is not well suited for this, but if even VB gives you the option to use them with its clunky syntax... I see it as a living proof that this should be welcomed also in Monkey :)

This VB code looks neat anyway, but I'd prefer to see at least a symbol separating the lambda body from the head.


Agreed to some extent; VB's awkward syntax for Lambdas is what led me to request a syntax somewhere between VB's and Ruby's. Use symbols in a way that's familiar / BASIC style for params, and keywords to bookend the lambda block, except in cases of single-line lambdas, which would obviously omit the "End" part of the block and only have keywords to mark the start of the parameter part and the expression part.

Maybe the expression keyword marker could be omitted in single-line lambdas but I consider this to be bad form, as evidenced by how strained VB syntax sometimes looks when performing an anonymous function. BASIC is considered overly verbose by many non-basic coders. It's simply verbose in ways many BASIC coders prefer -- it can be terse in other ways that C-style languages can't be, but it's a matter of preference and style as to what sorta verbosity is preferred where and that sorta style argument needs to strike a balance that's considered both true to BASIC and true to Monkey.

'Return statement could be optionally omitted?  I still think omitting the separator looks ugly and will make nested Lambdas look like crap...
'Think of it as a syntax sweetener
Local sum = Lambda( a:Int, b:Int) Returning a+b   

Local fact = Lambda:Int( n:Int) 
  If n <= 1 Then Return 1 Else Return (n * fact(n-1))
End Lambda


I stuck with Lambda as a keyword distinct from Function because Mark said there was a technical distinction from a true Function and whatever sorta technique he was using to implement anonymous functions / closures / lambdas / whatever. I'm not gonna claim I fully understand the distinction, but having a separate block seems good anyway, since we use two different keywords already to differentiate static methods and instance methods. Moreover, Function's also used to declare a general subroutine outside of an object class.

So, let's think like a Monkey here -- Method's used with a syntax that reflects its meaning, and Function can be argued to be used for two technically different contexts. Shall we extend that to 3? Or, is the way that anonymous functions disrupt typical syntax flow enough to say "BASIC coders are likely to want to know that this is a similar, but different use case scenario and not just really weird Function syntax"?

Newbies can easily look up the meaning of a Method and a Function (Actually a subroutine; although I'm glad we went with the term "Function" instead of "Sub" because this eliminates the weird "Sub=Func or Method returning Void" thing that VB users know and non-VB users hate). The keywords are easily found on Wikipedia. Someone new to anonymous functions may not know where to look the first time they see one. I know I didn't, coming from a VB background, when I first saw one in VB's syntax. That's because anonymous functions share keywords with methods and subroutines but have quite a different syntax than the context the keywords are usually expected to be in. I personally consider that to be a bit "Un-BASIC-like".

Edit: You may have noticed me changing large parts of this message as I try to sharpen my argument from my increasingly unclear mind :)


Pakz(Posted 2015) [#114]
All these features are Nice and all but without good short examples per feature it is not something I would use. I wil probably make a hundred or so examples with the new language on a blog but I Will have to learn it first. I used java for two years and did not even learn how to use oo. The documentation and examples for that language is very limited I experienced.
Examples that i find usefull are short examples that show how to use a feature and what it can be used for. If you already know how to use something or are good at figuring that out you would probably find it easy to learn a language. I do not know that much About modern features and need good docs and examples to learn how to use these things.

Keep in mind that there needs to be good documentation/examples. Luckely there is a forum with help, but it takes time for it to fill up with Answers and examples.

If I would consider patreon support then it would be becourse there is good docs and examples.


Dabz(Posted 2015) [#115]
He could always put a wiki thing up on the site and the people who have sponsored his patreon thing can add/edit stuff in there, obviously, there will need to be a "verify" post thing so it cannot be smashed to bits by a huffed user... Bet it would sharp stack up with examples and what not!

That would indeed take away the "awful docs" whinge that happened when BMax was released!

Dabz


itto(Posted 2015) [#116]
I would like to stop for a moment on something which bugs me. I see many people here "True to BASIC." I'd like to understand this. What does Monkey have to do with BASIC now? What is it that makes it BASIC-like? Cause to me, it doesn't look like BASIC at all. BlitzBasic did, but Monkey? The usual If...Else, For, Function... maybe While. Then? Uppercase keywords?

This is how TED auto-corrects your code:

Function MyFunction:Bool(param1:Int, param2:Float, param3:String)
    
    For Local x:= 1 To 10
        ...
    Next

    If param1
        ...
    ElseIf param2
        ...
    Else
        ...
    EndIf

EndFunction


But Monkey code can also be written like this (I do):

function MyFunction:bool(param1:int, param2:float, param3:string)
    
    for local x:= 1 to 10
        ...
    next
    
    if param1
        ...
    else if param2
        ...
    else
        ...
    end

    if param1 then ...     ' <- OMG missing End keyword!!

end


Suddenly it doesn't look so BASIC-ish anymore.

Why The Uppercase Madness? Does It Make Everything More Readable? THE ORIGINAL BASIC WAS WRITTEN LIKE THIS... GOOD TIMES :)

Is putting an End statement after a function declaration or conditional logic block making it a BASIC-like language? Then Ruby has a BASIC-like syntax too. Single line statements or newlines of significance to the parser? Then Python is on the boat, too. However, they both have a friendly syntax for the beginner, but also advanced power features with more unconventional (for the BASIC user) syntax where needed. If you are a newbie or don't want to use them, you simply don't use them and you won't see the awkward syntax in your code. But if you want more out of your language, it won't disappoint you.

This is Ruby (could be any other language)
class Dog  
  def initialize(breed, name)  
    # Instance variables  
    @breed = breed  
    @name = name  
  end  
  
  def bark  
    puts 'Ruff! Ruff!'  
  end  
  
  def display  
    puts "I am of #{@breed} breed and my name is #{@name}"  
  end  
end


But this is Ruby, too
Hash["a" => 100, "b" => 200]         #=> {"a"=>100, "b"=>200}

["one", "two", "three"].map {|n| puts n.upcase }


And this is Ruby also. Notice how the "do |...|" sintax in this example starts a block terminating with the "end" keyword. It's not so awkward as it may seem at first.

class Doctor
  ["rhinoplasty", "checkup", "interpretive_dance"].each do |action|
    define_method("perform_#{action}") do |argument|
      "performing #{action.gsub('_', ' ')} on #{argument}"
    end
  end
end


The first example is basically Monkey with some keywords changed and without fields declaration. The second example features a lambda, and it's as readable as it could be, without any useless character or symbol, between || you have arguments and after that the code to be executed. The third one features some magic. If you want to use the scary stuff, it's there for you to use. If you don't want, you won't see the awkward syntax.

I'm not complaining about the syntax of Monkey. I'm trying to understand what is it that prevents Monkey from getting power features if they don't please the BASIC spirit.

Generics can also be considered a power feature, not everyone understands how to use them at the beginning, but then they simply don't use them, and don't have to deal with the <> syntax at all. So why can we have <> but not {} or some other symbol exactly? (Always talking about single line statements, so having {} in the same line, like <>) If <> was a necessary introduction to implement generics, and it has been added, I don't see why we can't add |...|, {...} or whatever else suits the addition of a new language feature.

I think if we want to push things forward and have a more powerful language at our disposal, we should try to leave behind this whole BASIC thing. I mean, the focus can still be having a readable, structured and novice-friendly language, simple to use but powerful at the same time, even if it's not exactly BASIC-like.


skid(Posted 2015) [#117]
Why The Uppercase Madness? Does It Make Everything More Readable? THE ORIGINAL BASIC WAS WRITTEN LIKE THIS... GOOD TIMES :)


I concur. I have better things to do with my time than depress a shift key 2000 times a day.

The site design also seems to suffer the same insult to us of lower case.


taumel(Posted 2015) [#118]
I'm all in for a "readable, structured, novice friendly language which is simple but powerful at the same time". Yep, it doesn't need to be Basic and i also don't type uppercase commands where i don't need to but ... i'm still no fan of curly braces. () [] <> look better than {} to me, although their usage in Monkey, due to end, could be more limited and as i'm typing, a few small things:

Con instead of Const : Just three letters like Var (or like let in Swift).
^ instead of Pow : To me ^ is closer to +-*/ than a function (sin/cos).
Consistent random functionality (including integer versions).
I'm more used to Time than Millisecs.
Multiple return values for functions.
Multidimensional arrays.
:


Samah(Posted 2015) [#119]
@PixelPaladin: Implementing functions as classes could also solve many problems. Here is an example for functions with optional parameters:

Trans from Monkey 1 could be hacked to do this, and a few years ago I was actually planning it out. It was tricky at that stage since Monkey wasn't yet open source, so there was little chance of it becoming "official".

@ziggy: Local isPossitive := Function(value1:Int) value1>=0

This is nice.

@ziggy: Too much verbosity with no tangible benefit

I agree.

@Nobuyuki: I stuck with Lambda as a keyword distinct from Function because Mark said there was a technical distinction from a true Function...

I don't see the difference other than usage. Both are first-class blocks of code that (optionally) accept parameters and (optionally) return a value.
The only difference I can see is that a lambda implementation probably wouldn't have access to variables in the enclosing scope(s).
Please correct me if there are reasons to keep the concepts separate.

@Pakz: All these features are Nice and all but without good short examples per feature it is not something I would use.

If there's a place to put language examples, I'm quite happy to write a bunch.

@Pakz: I used java for two years and did not even learn how to use oo.

...what? o_O

@Pakz: The documentation and examples for that language is very limited I experienced.

I would say the complete opposite. There are more examples, documentations, and libraries available for Java than most other languages.

@itto: I'd like to understand this. What does Monkey have to do with BASIC now? What is it that makes it BASIC-like? Cause to me, it doesn't look like BASIC at all.

I kind of agree with this. Coming from a Java/C background, I find keyword soup to be very verbose and personally harder to read. Using mostly symbols is cleaner and less to type.

@itto: THE ORIGINAL BASIC WAS WRITTEN LIKE THIS... GOOD TIMES :)

Maybe strict should enforce all uppercase. :D

@taumel: Con instead of Const

It's too hard to type two extra letters? o_O

@taumel: ^ instead of Pow

I agree with this, or perhaps a double asterisk. (2**10 as opposed to 2^10)
It'd be nice for an exponent operator or keyword too.
123 Exp 5 = 123 * 10^5


@taumel: Consistent random functionality (including integer versions).

What do you mean? The pseudorandom algorithm used by Monkey is consistent across all targets.
Also if you want some more advanced random utilities (still cross-platform), check out my RandomSource class in Diddy.
https://github.com/swoolcock/diddy/blob/master/src/diddy/math.monkey

@taumel: I'm more used to Time than Millisecs.

But that's a bit too ambiguous. What does Time return? Seconds? Milliseconds? Nanoseconds? A structure containing all three?

@taumel: Multiple return values for functions.

This is going to be awful to implement, and I think Mark should just focus on pointers instead.

@taumel: Multidimensional arrays.

Ehhh.... I guess. I've never liked them, myself.


therevills(Posted 2015) [#120]
Using mostly symbols is cleaner and less to type.

If I wanted something like that I would use BrainF*ck!!
,>,< [ > [ >+ >+ << -] >> [- << + >>] <<< -] >>



itto(Posted 2015) [#121]
@therevills If I wanted something like that I would use BrainF*ck!!


Not sure if ironic or not, but I think some efforts should be really spent trying to reduce the verbosity of the language. Longer keywords don't benefit anyone if there can be a shorter equivalent. The less your eyes have to move to understand a piece of code (both horizontally and vertically), the more focused you can be on the problem at hand.

class myClass extends baseClass implements IDisposable


in C# would be written as

class myClass : baseClass, IDisposable


Same effect, much less verbose. Method declarations don't even use the "method" keyword. What's that for anyway? You are inside a class, except for an optional "public" or "private" keyword, the first thing you'll encounter is the method name anyway. Why having to prepend each method with the "method" keyword and each field with the "field" keyword? If we really need to tell the compiler where we are, or we really want to use them, then let's use them only once. We have the possibility to use the private or public keyword only once to create a scope from that point onwards, contrary to Java or C# where you have to declare the visibility of each method, so why can't we do the same to create a methods and fields block?

class myClass

    public methods:

    goThere:void()
        ...
    end

    doThat:int()
        ...
    end


    private methods:

    countToTen:void()
        ...
    end


    private fields:

    a:int = 1
    b:myClass = null
    c:float

end



Samah(Posted 2015) [#122]
@itto: ...contrary to Java or C# where you have to declare the visibility of each method...

I like declaring the visibility of each method. It means I can group code by functionality and not by visibility.


therevills(Posted 2015) [#123]
@itto:
class myClass extends baseClass implements IDisposable

in C# would be written as

class myClass : baseClass, IDisposable

Same effect, much less verbose.


And IMHO much less readable and you've just pointed out one of my pet hates about C#:
class Foo: Bar

Is Bar a super-class or an interface!?!?!

Which market is MonkeyX/MonkeyX2 aimed at? Beginners or advance programmers? I'm a professional software engineer by trade and I prefer readability over anything!


Skn3(Posted 2015) [#124]
I like declaring the visibility of each method. It means I can group code by functionality and not by visibility.

Ditto!

I think where Monkey1 excels in the areas where it has made code less "lazy". Functions/classes/methods/fields/etc only have to be defined once. It is more sensible to be strict here as it makes for a much cleaner language. It is not as if you have to declare it public/private/protected every time you use it!

class myClass extends baseClass implements IDisposable


If MX2 allows multiple inheritance (dunno if that has been confirmed?) then surely implements and extends can be merged into something like "uses" or "from"?

class MyClass From baseClass,IDisposable


The compiler would just pick the behaviour from the destination instead of the keyword.


Nobuyuki(Posted 2015) [#125]
I guess attacking the whole "spirit of BASIC" thing is the first step to encouraging symbol soup or making the language more C-like in the guise of reducing verbosity or some other nonsense. I'm with therevills on this one. Why shouldn't we try to aim for readability to novice users, even for more powerful features? I don't consider code so thick that I have to analyze every symbol for context particularly readable -- I'm not a mathematician.

And hopefully I can pre-empt the expected response of someone coyly suggesting we either 1. be more 'basic-like' by adopting some obsolete convention, or 2. attempting reducio ad absurdum by making something as overly verbose and pointless as possible. Let's not do that :)


Oh, and itto: Monkey's syntax and conventions resemble VB.NET quite a bit. If you feel that BMax resembles BASIC more than Monkey does, I'd venture to say that you haven't worked with any modern dialects for quite a while.... I don't want to believe that though, it's just that I'm surprised you'd make the supposition !


Skn3(Posted 2015) [#126]
And hopefully I can pre-empt the expected response of someone coyly suggesting we either 1. be more 'basic-like' by adopting some obsolete convention, or 2. attempting reducio ad absurdum by making something as overly verbose and pointless as possible. Let's not do that :)


I think we should go back to adding line numbers to our code!

I like Monkey's mix of basic-like and non-basic-like syntax. It is a pleasant blend of both worlds. A few more keywords here and a few more symbols there, it's going to be fine. I think people might be getting a little ahead of the game. Realistically Mark is not going to turn the new language into SpagettitBrainFock++


itto(Posted 2015) [#127]
@Noboyuki I guess attacking the whole "spirit of BASIC" thing is the first step to encouraging symbol soup or making the language more C-like in the guise of reducing verbosity or some other nonsense.


I was trying to understand what this BASIC spirit was about, not attacking it :) And I'm not trying to suggest we should turn the language into a C-like one, far from it.

Monkey's syntax and conventions resemble VB.NET quite a bit. If you feel that BMax resembles BASIC more than Monkey does, I'd venture to say that you haven't worked with any modern dialects for quite a while.... I don't want to believe that though, it's just that I'm surprised you'd make the supposition !


You're right, I haven't worked with any modern BASIC dialects in the past 10 years or more (unless you consider PureBasic, not sure if it's modern or not). Having discovered the power of more advanced languages, a language whose syntax to implement Lambdas makes them almost unusable doesn't seem particularly exciting to me. You are able to implement callbacks with PureBasic using pointers, you can imagine the hell which can result from that. So in 2015, VB still doesn't seem relevant to me given it's clunky and limited. But if you want to point me to a modern and powerful BASIC dialect, I'll be happy to take a look :)

Anyway I said to me it resembles BlitzBasic (and not BMax, which I didn't use), because I wanted to point out that to me this Monkey language is far from the old BlitzBasic in terms of syntax. What I feel is that it kinda moved away from the early BASIC languages, so I was wondering if it were trying to go further away from it.


ziggy(Posted 2015) [#128]
Same effect, much less verbose. Method declarations don't even use the "method" keyword. What's that for anyway? You are inside a class, except for an optional "public" or "private" keyword, the first thing you'll encounter is the method name anyway. Why having to prepend each method with the "method" keyword and each field with the "field" keyword? If we really need to tell the compiler where we are, or we really want to use them, then let's use them only once. We have the possibility to use the private or public keyword only once to create a scope from that point onwards, contrary to Java or C# where you have to declare the visibility of each method, so why can't we do the same to create a methods and fields block?
That was implemented like this in C++ compilers to make it easier to have a single pass parser (palm face and now go and think on Macros, but that's another story...). The thing is that this is a ver bad design idea, and that's the reason nor Java or C# or VB.net or Scala or D or most modern languages do not do it like this.
The reason is very simple: It's not a good idea to be forced to group class members by a visibility criteria. It's better to be able to group them by a functional criteria, and that's specifically important when it helps understand the class logic as it reduces maintenance costs and makes developer's life less miserable better.

The idea of a having a Public or Private identifier following all public or private members is IMHO as stupid to me as removing datatype from function declarations, and putting a single "Return Int" followed by all functions that return an integer, then a Return String followed by all functions that return a String, etc etc. It will reduce verbosity too, but it's not exactly elegant.

I'm saying this because the fact that a function (or any other member of a class) is public or private is a given attribute of the member itself. Defining this anywhere else is very disgusting. The thing is that, we're sort of used to it because that's what we've all learned from C++, but this does not make it a good idea.

Also, I could agree that too much typing is a bad idea, but information dispersion is a worse idea. We could consider the usage of short operators to define class memebers visibility in roder to reduce typing, but this would come at the cost of making the language less readable which is something I'm not sure it's worth it.

C++ as a language has lots of good things we could use, but syntax is not exactly their best contribution to languages design.

If MX2 allows multiple inheritance
Well, unless you're talking about interfaces... hell no!

Then, now a request as if I was writting a letter for Santa... Please, allow for some sort of Unit Testing. Maybe "just" using reflection to allow the creation of Mocks and a simple Assertion class or similar, or a module that automates the creation of mocks from interfaces where all methods are implemented as delegates pointing a default empty method would be enough and would allow for UT by redirecting those delegates... ?


Skn3(Posted 2015) [#129]
Well, unless you're talking about interfaces... hell no!


Insert 101 ways to make an IDE developers life a living hell ;)


ziggy(Posted 2015) [#130]
@Skn3: Well, I have to support it for Interfaces so not a big deal, I was thinking more of the line of this: http://stackoverflow.com/questions/406081/why-should-i-avoid-multiple-inheritance-in-c (It's very well explained there, but there are countless of resources).

Most proper OO languages that I know of, do provide interfaces to grant that a class can implement multiple contracts as long as it retrieves a single responsibility and follows Dependency Inversion principle as much as possible.
Following dependency inversion by extending a base class is impossible, but somehow accepted. Adding 2 or more classes to the party is very smelly and can be considered bad design. (see this too http://en.wikipedia.org/wiki/Dependency_inversion_principle#Abstraction_dependency )

Also see the Diamond of death problem http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem


Nobuyuki(Posted 2015) [#131]
@itto
You're right, I haven't worked with any modern BASIC dialects in the past 10 years or more (unless you consider PureBasic, not sure if it's modern or not). Having discovered the power of more advanced languages, a language whose syntax to implement Lambdas makes them almost unusable doesn't seem particularly exciting to me. You are able to implement callbacks with PureBasic using pointers, you can imagine the hell which can result from that. So in 2015, VB still doesn't seem relevant to me given it's clunky and limited. But if you want to point me to a modern and powerful BASIC dialect, I'll be happy to take a look :)


Right you are. VB.NET is "modern" perhaps only in the 2005 sense, and Lambdas in that language look like an afterthought. That being said, in terms of its capabilities, seeing as it's designed by most of the C# team now, about the only thing C# can do that it can't are pointers, and most people don't care about them when writing new code, nor want to deal with them. (Insert stuff that's already been said a zillion times about Delegates here.)

I'd venture to say that Monkey's the "most modern" BASIC dialect which exists right now. That's a very large weight to carry on its shoulders, for sure. I personally believe that it's important it carries this torch and doesn't abandon some of the principles which make it what it is -- easy to read and understand at a glance, even by non-programmers, powerful and versatile, and -- in the case of Monkey specifically -- terse where it's appropriate (like with type declarations and with Generics!), and also verbose when it's appropriate. I honestly wouldn't mind seeing Ruby's lambda syntax in mx2, although I think we can do one better than that, and especially do one better than how it was implemented in VB.NET.

@skn3
I like Monkey's mix of basic-like and non-basic-like syntax. It is a pleasant blend of both worlds. A few more keywords here and a few more symbols there, it's going to be fine. I think people might be getting a little ahead of the game. Realistically Mark is not going to turn the new language into SpagettitBrainFock++


Agreed. My apologies if it sounds like I'm getting hung up on an ideological argument.


@ziggy
+1 to no MI. What terrible design patterns that can lead to. Interfaces definitely seem like the right way to go here, even though maybe the contracts can be relaxed some (or made more "magically dynamic" to allow some sorta inference or casting in the cases of containers, structs and things like that...)


taumel(Posted 2015) [#132]
@Samah
Const:
Vertical alignment

RND:
If i remember things correctly, i wasn't getting the same results on various platforms i once gave a try.

Time:
I would like to have a couple of static variables f.e. like in Unity (time in seconds, milliseconds if you want to, deltatime, framcount, etc.) Things you need over and over again, so, it makes sense offering a core bunch of them via time.

Multiple values:
But it can be so handy.

Multidimensional arrays.
Sometimes you want them, sometimes you don't but when you want them then you really want them and just type away.

Oh, and you should have called your framework Voodoo instead of Diddy. ;O)


Gerry Quinn(Posted 2015) [#133]
Ziggy said: "It's better to be able to group them by a functional criteria, and that's specifically important when it helps understand the class logic as it reduces maintenance costs and makes developer's life less miserable better."

But Ziggy, what if your class is done, and somebody is using it. Surely the Public methods are the relevant ones, and unless they want to re-write your code, they don't need to know about any other methods? Did you not design your class so that for most users, the public methods will be the only relevant ones?


Skn3(Posted 2015) [#134]
@nobuyuki
Agreed. My apologies if it sounds like I'm getting hung up on an ideological argument.

Oh it wasn't directed at you, even though the way I wrote the post probably sounded like it.

It was directed in general. It seems that in this thread and some others a few people sounding overly concerned of all the new bits coming.

@ziggy
Interesting links. I have only ever been in a situation where I needed to use multiple inheritance once. I was trying to make a general purpose base object that all engine objects stem from. The base class would offer things like built in variable debugging, id, messaging, etc. there were then other extended "root" classes which each added additional features for a specific category of engine object.

The issue came when I wanted to further extend down the tree and pick and choose functionality from two of these root categories. I could move the shared code up the hierarchy, but eventually you end up with one super object. Lots of wasted memory usage and generally not good.

I worked around it fine, but it was probably the only time MI would have been useful!


Samah(Posted 2015) [#135]
@Skn3: If MX2 allows multiple inheritance (dunno if that has been confirmed?)...

If it does, I will abandon all hope for the language and dig my eyes out with a rusty spoon.

@Skn3: ...then surely implements and extends can be merged into something like "uses" or "from"?

More keywords? Urgh...

@taumel: Const:
Vertical alignment

Formatting is a poor argument for keyword selection. Would you also like "fld" and "glb"?

@taumel: RND:
If i remember things correctly, i wasn't getting the same results on various platforms i once gave a try.

Monkey's Rnd() implementation is written in Monkey, not native code, thus it performs the same on all targets.
Function Rnd#()
	Seed=(Seed*A+C)|0
	Return Float(Seed Shr 8 & $ffffff)/$1000000
End
'where A and C are constants

If you're getting different values then you've probably got a rounding problem somewhere that's unrelated to the Rnd implementation.
Are you using the same seed for all targets?

@taumel: Time:
I would like to have a couple of static variables f.e. like in Unity (time in seconds, milliseconds if you want to, deltatime, framcount, etc.) Things you need over and over again, so, it makes sense offering a core bunch of them via time.

Sure, but as soon as you start returning things like delta time and frame count, it moves into the world of Mojo 2. The C++ Tool target for Monkey 1 would not be able to give you a delta time or frame count, because there is no main loop.
Having said that, values that you can retrieve directly from the system clock regardless of frameworks would be useful, such as "seconds since the epoch" and "milliseconds since the program started" (current implementation of Millisecs).

@taumel: Multiple values:
But it can be so handy.

Implementation is horrendous, though. To translate to languages with no support for multiple return values, you'd need to have an internal tuple data type to hold them. That's fine if the language supports structs, but any other target language is going to have overhead as you create temporary arrays or wrapper objects. It's more work than it's worth, IMO.

@taumel: Oh, and you should have called your framework Voodoo instead of Diddy. ;O)

Voodoo was my original working title for Diddy. Blame therevills for the name change. :)

@Gerry Quinn: ...Surely the Public methods are the relevant ones...

This is where documentation and autocomplete come in. Also any decent IDE will allow you to sort by visibility in its outline view. Pretty sure Jungle does this for you.


nullterm(Posted 2015) [#136]
I'd rather have Struct return values (via the stack, not heap like Classes) than multiple return values (ie. tuples in Python).


ziggy(Posted 2015) [#137]
Surely the Public methods are the relevant ones, and unless they want to re-write your code, they don't need to know about any other methods? Did you not design your class so that for most users, the public methods will be the only relevant ones?

Well, the fact that public methods could be considered the relevant ones would not make it better to be forced to group them by visibility. but in the real world, people can work on teams and deliver source code to others that can not only use it, but also extend and maintain it, so they'll need much more than the public interface of the class. Sometimes people will need to understand the class internals. Even the "you of the future" will surely at some point!


Gerry Quinn(Posted 2015) [#138]
Well, sure, I am not arguing about people having access to the class internals. But to my mind, understanding the class starts with understanding its purpose, which should be transparently exemplified by its public interfaces
















.


Skn3(Posted 2015) [#139]
@samah
If it does, I will abandon all hope for the language and dig my eyes out with a rusty spoon.

hahaha, made me remember Salad Finger...



+1 also for voodoo diddy :D

Still think the new Monkey should be called Voodoo, and the framework Mojo!

@multiple return values
This would be a really useful feature, but it definitely is not the making of a clean language. In teh programming world it is is a infrequently seen practice (in comparison to single return), so you instantly add learning curve. But to be honest something like...
Function Move:{Int, Int}(x:Int, y:Int, amount:int)
	x += amount
	y += amount
	Return x, y
End

.. this is fine, the nasty bit comes when you want to assign/use those values...
Local {newX:Int, newY:Int} = Move(5, 5, 1)

If Move(2, 2, 1){1} = 3
	
EndIf


not great!


Shinkiro1(Posted 2015) [#140]
@Skn3
I was all for multiple return values but your example convinced me otherwise.

It adds complexity, by making you constantly think if a function returns 1, 2 or more values. Also the mapping might get confusing.
Because as you said 99% of the time you will return a single value, why make the lang more complex for the rare cases.

---

edit:
I also think that executing code before compiling would be very helpful, commonly also called compile time evaluation. It can be useful for optimization (evaluating expressions at compile time), you can run scripts before the game runs, you could even create a compiler on top of mx2 that then converts to standard mx2. Lots of possibilities.

Got the idea from the D language. Relevant SO question: http://stackoverflow.com/questions/11452791/whats-the-use-case-for-ds-compile-time-evaluation?rq=1


ziggy(Posted 2015) [#141]
It adds complexity, by making you constantly think if a function returns 1, 2 or more values. Also the mapping might get confusing.
Because as you said 99% of the time you will return a single value, why make the lang more complex for the rare cases.
Using Structures for this is nicer if you ask me


Shinkiro1(Posted 2015) [#142]
> Using Structures for this is nicer if you ask me

Completely agree.


taumel(Posted 2015) [#143]
@Samah
See, from my point of view all the things i've listed (and i could throw in some more) make sense due to various reasons. I don't differ between which module they belong to. For me Monkey 2 is one thing, not a language here and module for this those and that there. I'm interested in the overall end user experience.

Regarding Voodoo/Diddy
I know, you wrote this somewhere here. I guess you have a new chance with Monkey 2.


Gerry Quinn(Posted 2015) [#144]
Even now you can return an array - it's a little bit clunky and limited but it's one way to implement multiple return values.


Raph(Posted 2015) [#145]
Lua does multiple returns pretty cleanly, IMHO. http://www.lua.org/pil/5.1.html


Samah(Posted 2015) [#146]
@taumel: For me Monkey 2 is one thing, not a language here and module for this those and that there. I'm interested in the overall end user experience.

Well it's multiple things for me, so we'll have to agree to disagree.

@Gerry Quinn: Even now you can return an array - it's a little bit clunky and limited but it's one way to implement multiple return values.

Unfortunately it creates an object every time you do it. :(


impixi(Posted 2015) [#147]
To be honest I don't see the need for multiple function returns in an object oriented language. I'd be more inclined to design my code around encapsulation principles.

Take the Swift example:

    func minMax(array: [Int]) -> (min: Int, max: Int) {
        var currentMin = array[0]
        var currentMax = array[0]
        for value in array[1..<array.count] {
            if value < currentMin {
                currentMin = value
            } else if value > currentMax {
                currentMax = value
            }
        }
        return (currentMin, currentMax)
    }


In a non-OO, non-multiple return results language like C I'd do something like this:



You could port the above to Monkey, making use of a pre-existing class instance passed as a parameter to to MinMax. However, I'd be more inclined to code the desired behavior within a class.




marksibly(Posted 2015) [#148]
Regarding the public/private block/decl issue - how about we allow both? eg:

method OnDraw:void() protected

protected could potentially go at the front, but I think that could be confusing to people used to block style. Also, it's more monkey-ish for modifiers to go at the end.

This wouldn't affect the block state, just the one decl.

Sound OK?

I don't think there's a right/wrong answer to which is 'better' here - people's experience will have FAR more influence over what they're comfortable with I think. But the block style will remain, as I'm just too used to it.


Samah(Posted 2015) [#149]
@marksibly: Regarding the public/private block/decl issue - how about we allow both?

Actually that's a pretty decent idea. I'd go for that.


Richard Betson(Posted 2015) [#150]
To be honest I don't see the need for multiple function returns in an object oriented language

I have to agree with that.

Have we talked about arrays? I would like to see multidimensional arrays in even if it is really a convince. Casting arrays of arrays somehow seems weird to me.;)


taumel(Posted 2015) [#151]
When you're taking a look at different (OOP) languages then it's obvious that there is a need for returning multiple values via certain functions. Only a few try to solve this directly, others use structs/tuples/outside vars/... to support this. Certainly a feature you benefit from in practice, if properly implemented.


Samah(Posted 2015) [#152]
@taumel: When you're taking a look at different (OOP) languages then it's obvious that there is a need for returning multiple values via certain functions.

Only if it can be flawlessy implemented with a clean syntax and no unwanted side-effects. Structs/value types are good enough, I think.


ziggy(Posted 2015) [#153]
@taumel: When you're taking a look at different (OOP) languages then it's obvious that there is a need for returning multiple values via certain functions.
Being pedantic, It's not obvious to me. I mean, if a method returns 2 unrelated values, it should be 2 different methods. If it returns a complex value with different fields, it should be expressed in the method signature with the interface that expresses the complex data returned, and this method should return any instance of a class that implements its signature interface. That's what I think a better way to deal with complex values and keep inversion of dependencies in the design, which is always better in the long run!


taumel(Posted 2015) [#154]
Why should they be unrelated? It just can be a lot more handy and readable, imagine dealing with vectors.


Nobuyuki(Posted 2015) [#155]
@marksibly
Regarding the public/private block/decl issue - how about we allow both?


+1. Then it's a matter of style guidelines for the individual coder. I'm used to how it is now and I think it looks way cleaner but I'm guessing at least a few people (especially newcomers to monkey) are going to tag the heck outta things, whether it be from force of habit, ingrained dogma or whatever. I don't see the problem with letting 'em if the worst it can do is look ugly.

@taumel
Why should they be unrelated? It just can be a lot more handy and readable, imagine dealing with vectors.


I'm imagining.... a Struct!


Samah(Posted 2015) [#156]
@Nobuyuki: ...if the worst it can do is look ugly.

Personal opinion. I hate having to scroll up to see what the visibility is for a given class member. For me it's much easier to just look at the method signature.

@Nobuyuki: I'm imagining.... a Struct!

That's strange... so am I! :)


ziggy(Posted 2015) [#157]
Why should they be unrelated? It just can be a lot more handy and readable, imagine dealing with vectors.
If they're a vector they're NOT 2 unrelated values, they're a vector. a 1 vector. That's a 1 complex value. Dealing with them using separate variables is not exectly OOP design, that's what I was saying!


itto(Posted 2015) [#158]
Sorry everyone, I didn't expect to create a fuss about the visibility block issues. It's not that important, really.

@marksibly method OnDraw:void() protected


Wait, are you saying we will have protected members finally? Perhaps I missed some posts :)

@ziggy Then, now a request as if I was writting a letter for Santa... Please, allow for some sort of Unit Testing.


THIS!


Shinkiro1(Posted 2015) [#159]
Public/Private:
I don't like the way C++/Java/C# do it. It's too verbose and feels like filling out tax forms.
public static void main


I think it's more important to first see if something is a method, function, field, etc. than if it's private or public.

PS: I just put private stuff at the bottom of a class.
This way I have an easy mental model: "this is stuff I can't call from outside this module".


itto(Posted 2015) [#160]
@Shinkiro1 PS: I just put private stuff at the bottom of a class.
This way I have an easy mental model: "this is stuff I can't call from outside this module".


I follow a similar approach, but for another reason. The public members go at the very top of a class, because they define the class interface to the external world. They are more likely to be checked out by the user of the class. Then comes the protected and private members, in that order, because they go deeper into the class internal workings. I think I read a similar approach in one of Uncle Bob's books, but I may be wrong.


taumel(Posted 2015) [#161]
@Nobuyuki/...

Structs first need to be defined and their usage can be less flexibel.

When i was talking about vectors i didn't have one vector with its xyz components in mind, more a bunch of them being used for different purposes like a transform, a position and an orientation you receive from a curve (or after an alteration of the routine/purpose, another vector(s)), vectors you need for further calculations, vectors needed for proper vertices definition (including normals, tangents, ...), ... but let's just end it here, from my point of view it would be great, from yours not this much, we'll see if Mark thinks it could be handy.


Gerry Quinn(Posted 2015) [#162]
Just thinking aloud here (and like others are saying, Structs are the first step). If we had them, what about:



This could be done with ordinary objects that likely go on the heap too, though. Because the thing is, if you need to avoid memory allocation, you can easily rewrite the above to define a class explicitly to contain x1, x2 and x3, and keep an instance hanging around.


marksibly(Posted 2015) [#163]
> Sorry everyone, I didn't expect to create a fuss about the visibility block issues.

Nah, it's all good! If people have strong opinions about this stuff, I'd rather hear them than not.

> It's not that important, really.

Like lots of things, it's of differing importance to different people.


Samah(Posted 2015) [#164]
@itto: Wait, are you saying we will have protected members finally? Perhaps I missed some posts :)

Monkey has had protected members for a few months now.

@Shinkiro1: I think it's more important to first see if something is a method, function, field, etc. than if it's private or public.

I'll agree with this, though I have no problem with adding lots of keywords if they can go at the end as in Monkey/BlitzMax.

@Shinkiro1: PS: I just put private stuff at the bottom of a class.
This way I have an easy mental model: "this is stuff I can't call from outside this module".

I'm the complete opposite. I put all private members at the top of the class, so I can read it as "here's all the things I'm about to use in my methods".


Danilo(Posted 2015) [#165]
@Gerry Quinn:
C/C++ can return Structs. The returned struct is a hidden first argument then.

This code returns a struct:
// C++
struct Point {
    int x, y;
};

Point foo(int i){
    Point pt;
    pt.x = 10;
    pt.y = 10;
    return pt;
}        

int main () {
    Point p;
    p = foo(5);
    return 0;
}

For the function call "p = foo(5)", C++ compilers add the structure as hidden first argument,
so behind the scene it becomes:
Point p;
foo(&p, 5); // p = foo(5);


See also: Return value optimization

- Google: "return struct in c++ hidden first argument" -> https://www.google.com/#q=return+struct+in+c%2B%2B+hidden+first+argument


itto(Posted 2015) [#166]
@Samah Monkey has had protected members for a few months now.


I definitely did miss some posts :P

Structs as first class citizens would be amazing. If they will be implemented, I think they should be straightforward to write as arrays are now.

For example you can already do this in Monkey

function myFunction()
    return [
        1, 2,
        3, 4]
end

local myArray:= myFunction()
Print myArray[2]
' or even Print myFunction()[1]


For structs, I would expect something as straightforward, like

function myFunction(x)
    return [
        a => x,
        b => x * x,
        c => x * x * x]
end

local myStruct:= myFunction(5)
Print myStruct.c


(Whatever the syntax)

return {
    a: x,
    b: x * x,
    c: x * x * x}


If for various reasons that can't be accomplished (I didn't consider types in the previous examples), then a more cumbersome version could be

' predeclare the damn thing, okay...
struct myStruct
    field x:float
    field y:float
    field name:string
end

function myFunction:myStruct(x:float)
    return [
        x => x / 3,
        y => x / 5,
        name => "foo"]
end

function name:string(s:myStruct)
    return s.name
end


I don't know how structs behave in other languages under the hood, but it would be amazing if they could go on the stack avoiding the heap. Otherwise I don't see much of an improvement over using a simple class.


Gerry Quinn(Posted 2015) [#167]
I am like Shinkiro and Itto, I put the public members first and private last. I think those of us who do that are probably more likely to be fans of the current Monkey 'block' method.

Danilo, I frequently have used the pattern you mention in C++, I just didn't think of it as anything really different from returning an int. Historically, I suppose, a returned int is probably found in a specific machine register rather than on the stack, but the difference is transparent to the coder [Edit: in general, I guess people still probably mess with the SP occasionally!]. Of course, with C++ you just tell the compiler explicitly whether you want to use the stack or the heap, so there's no real difference between classes and structs except a default access qualifier.

I was just musing on a way the syntax could fit with Monkey.


Skn3(Posted 2015) [#168]
Regarding the public/private block/decl issue - how about we allow both? eg:

method OnDraw:void() protected


If adding for the sake of appealing to all, then consider is it worth adding two ways to skin a cat, just because not everyone agrees on the best way? Which way is more useful then the other. Or if easier, which way has more negatives?

A strive to make things easier, more crowd pleasing, can infact make things more complicated in the long run.

In my opinion I have always disliked blitz approach to privacy. You go to your function definition to look for the parameters and return type, so why not privacy? You go to a class definition to find out what it extends from; imagine if the extension definition was done this way... I know this has already been argued here, but it really would be a good area to tighten up the language a little.

I think with all definitions such as class/function/etc you should be as strict as possible. It just makes reading code easier. When dealing with "normal" code, within your functions, this is where it is good to be less strict. Mainly because you type a lot more "normal" code then you do definitions.


Gerry Quinn(Posted 2015) [#169]
"You go to your function definition to look for the parameters and return type, so why not privacy?"

Because privacy is functionally different? How about: "you look at what functions are available to use in the current context, and then you look at the function to see how to use it," If it's a private function and you aren't working with the class, you shouldn't be using it - and if you are working within the class, you can use any function regardless of access qualifier.


Shinkiro1(Posted 2015) [#170]
@Samah
I'm the complete opposite. I put all private members at the top of the class, so I can read it as "here's all the things I'm about to use in my methods".



That's still a nice mental model imo and not that different.
As long as fields and methods remain public by default though, I am fine with either solution.

I just fear people will be slamming public everywhere even if it's the default anyway.
Because it's more 'explicit' and of course writing all these words will make you a real programmer :P


dmaz(Posted 2015) [#171]
have varargs / variadic arguments been mentioned yet?


Skn3(Posted 2015) [#172]
Because privacy is functionally different? How about: "you look at what functions are available to use in the current context, and then you look at the function to see how to use it," If it's a private function and you aren't working with the class, you shouldn't be using it - and if you are working within the class, you can use any function regardless of access qualifier.


Its true it is functionally different, but it doesn't necessarily mean it should have a 100% different approach.

I do like the compromise approach that all functions are deemed public unless specified. If that was what you were suggesting? I do think though that MX2 should define private/public per function/method/class and not via separate public/private blocks. The current way means there is no RIGHT way to work. Some people could define privacy per function, some people at the top of a class and some people in blocks randomly throughout the class. The more options you give in this type of scenario, the messier user code can get.


Nobuyuki(Posted 2015) [#173]
@skn3
The current way means there is no RIGHT way to work.


I don't really get it. Monkey1 only has 1 way to define scope; if I'm understanding what you're implying, restricting it to one way or the other imposes a "RIGHT" way to work. This was done with Monkey1 -- some people didn't like it and that's where the whole scope syntax argument came from in the first place. Once Mark suggested a compromise for monkey2, at least one person has said they'd prefer enforcing explicitly on each definition be the only way and several more seem to be hinting at that, too. IE: He gives an inch, and now some people seemingly appear to be clamoring to push further in their direction.

Honestly, if there must be a canonical way, I'd prefer it be done the way Monkey1 does it, because it enforces a style of code I personally find cleaner. The way everyone else is suggesting is how VB.NET does it and after using Monkey for a while, I would not want to go back to it. Members are private by default there, and declarations are a PITA to write because it requires so much boilerplate. Maybe some people should reconsider their style choices, if their level of discomfort with the way it's currently done extends so far as to eliminate even the possibility that many/most people will use the existing syntax as the canonical style choice.

I have not heard a convincing argument outside of stylistic choice to enforce a new/different scoping syntax to mx2, even if it is more similar to some existing languages a few users are more familiar with. So far it sounds like people attempting to stretch their personal preference into something resembling an objective argument, and starting to bang the hammer of repetition after seeing a partial 'success' towards this end.

Edit: I want to add that this is one of the few places where I believe Monkey has made an improvement on VB in terms of readability while also reducing verbosity, particularly in class members. It screws with some people's mental models of how a class "should" look and I can understand why that rubs some people the wrong way, but Monkey's not the first nor the last language to use scoping directives in this way, nor where the "canonical" style organizes more by visibility than by functionality.

That being said, I think that both styles merit places where they can be used for the most convenience, particularly if there are a couple of variables that you just absolutely must place somewhere near a similar one of differing scope amongst a bunch of other members in the original scope. "Using the right tool for the job" is the pragmatic solution, and users who happen to make a mess of their class members do so at their own peril.

There seems to be a valid argument for both styles where enforcing one or the other imposes a greater cohesion to groups of variables in a given block, but generally speaking, I don't see ANYWHERE where an argument can be made for one way that can't be made for the other. So, my fallback for "not taking a compromise" is to keep the status quo. But at this point, I'd much like to be able to have the flexibility to do it either way, since I'm used to both and can see uses for limited mix-and-match usage patterns. I will continue to use the below style, however, in default situations:

Class Foo
  Private
    Field _myVar

  Protected
     'Protected vars here 

  Public
    'Globals here
    'Public fields here

 'Properties
  Method MyVarReadOnly() Property
    Return _myVar
  End Method

  'Non-property methods here

  'Functions here
End Class



Skn3(Posted 2015) [#174]
@nobuyuki

The code example you give is nice and neat. If all code was like this then it would be fine. The issue comes because not all code is guaranteed to come this way. That is what I meant in that there is no RIGHT way currently. If you ask the user to designate their privacy blocks, you end up with sometimes no privacy definition, sometimes neat, sometimes spread throughout a class in patches.

With enforced privacy per function/class, there is only one way to do it and it is uniform by design. In my eyes this is a plus. Maybe in other people's minds this is a negative. You are right, it comes down to preference. Both are suitable for the task, so it's really a futile conversation. Still worth voicing though ;)

Once MX2 is built, there is no going back on decisions like these...


Samah(Posted 2015) [#175]
Alternatively, make all the things public! \o/


marksibly(Posted 2015) [#176]
I quite like the Go approach...

function update()   'lowercase so private
end

function Update()   'uppercase so public
end


No idea how protected would work though!


Danilo(Posted 2015) [#177]
@marksibly:
That forces a specific naming style for Fields, Methods, Functions, and Properties. I don't like that.

Both mentioned Public/Private/Protected styles already compile with latest version 0.83c.
Strict

Class Foo
    Private Field _myVar:Int

    Public Field x:Int

    Public Method MyVar:Int() Property
        Return _myVar
    End

    Protected Field prot:Int

    Private Method MyVar:Void(x:Int) Property
        _myVar = x
    End
End

Class Bar
    Private

        Field _myVar:Int

    Public

        Field x:Int

        Method MyVar:Int() Property
            Return _myVar
        End

    Protected
        
        Field prot:Int

    Private

        Method MyVar:Void(x:Int) Property
            _myVar = x
        End
End

Function Main:Int()
    Local obj1:= New Foo
    Print obj1._myVar
    Print obj1.x
    Print obj1.prot
    obj1.MyVar = 10
    Print obj1.MyVar
    
    Local obj2:= New Bar
    Print obj2._myVar
    Print obj2.x
    Print obj1.prot
    obj2.MyVar = 10
    Print obj2.MyVar
    
    Return 0
End

It's already working like requested. ;)


Samah(Posted 2015) [#178]
@Danilo: Both mentioned Public/Private/Protected styles already compile with latest version 0.83c.

Correct, but that's no different to removing the newlines.
Public Field x:Int
Method Foo:Void(); End

Private Field y:Int
Method Bar:Void(); End

Is the same as:
Public
Field x:Int
Method Foo:Void(); End

Private
Field y:Int
Method Bar:Void(); End

Is the same as:
Public Field x:Int
Public Method Foo:Void(); End

Private Field y:Int
Private Method Bar:Void(); End


However, that raises a good point. If you ALWAYS give a visibility modifier, there's no problem. It's only if you mix and match that there could be conflicts.

Maybe leave it as it is? Both camps should be happy.


Danilo(Posted 2015) [#179]
Even a 3rd style, how cool is that? :)


marksibly(Posted 2015) [#180]
> That forces a specific naming style for Fields, Methods, Functions, and Properties. I don't like that.

I didn't expect anyone would!


marksibly(Posted 2015) [#181]
Actually, I'd quite like to enforce more end-of-statement separators this time around, so...

public method blah:int()

wouldn't work.

I guess I could special case public/private/protected?


Danilo(Posted 2015) [#182]
Another thing, Mark:
Could you allow declaration of Constructors ("Method New(...)") for Extern classes?

For my three.js import I have to add "CreateBlahBlah()" functions for all imported classes,
because external Constructors are not supported.
And adding a "Create()" function within the class also does not work, because the name is extended
with the class name:
Class PerspectiveCamera Extends Camera = "THREE.PerspectiveCamera"
    Function Create:PerspectiveCamera(args) = "CreatePerspectiveCamera" ' becomes automatically 'THREE.PerspectiveCamera.CreatePerspectiveCamera'
End

Or is there a special trick required?

Importing constructors would be nice, so we could directly do "cam1 := new PerspectiveCamera(args)"


degac(Posted 2015) [#183]

I quite like the Go approach...



No! Please! It's just difficult (for me) understand lower/upper case words in a source... now if you add this you can call it 'EvilX' language!


Nobuyuki(Posted 2015) [#184]
quick show of hands: Of those of you who like the scope directives on the same line as the declaration, would you prefer it appear at the beginning of a line (as with the Monkey1 trick), or grouped where declaration modifiers would usually go? Where would it be more syntactically consistent? Consider this pattern:

Class MySingleton
'Prefix
  Private Global shared_var:Int
  Public Method DoNothing:Void() Final Property

'Postfix
  Global shared_var:Int Private
  Method DoNothing:Void() Public Final Property
End Class


Edit: I guess if Property syntax were to get changed into a "Property..Getter..Setter..End Property" thing, this example would be less relevant, but you could still end up stringing multiple modifiers depending on the type of class/interface you're making...


dmaz(Posted 2015) [#185]
for consistency it really should be on the end otherwise why isn't this an option?
Class MySingleton
  Private Global shared_var:Int
  Public Final Property Method DoNothing:Void()
'or
  Public Final Property DoNothing:Void()
End Class

which I might kind of like
[edit] because it puts the arguments at the end


ziggy(Posted 2015) [#186]
I quite like the Go approach...
Me too! But I have the same problem with protected. underscore prefix maybe? (I know no one will like it, but I found it to be concise, not ambiguos and very non verbose at the same time).


dmaz(Posted 2015) [#187]
Me too! But I have the same problem with protected. underscore prefix maybe? (I know no one will like it, but I found it to be concise, not ambiguos and very non verbose at the same time).
I hope lack of sarcasm quotes was just an over sight.


Samah(Posted 2015) [#188]
@ziggy: ...underscore prefix maybe?

Leading underscore in my code generally means "this is a dirty hack, please don't touch it or something will break". Other than that I hate them.

@Nobuyuki: ...quick show of hands...

Coming from a Java background, I prefer them at the start, but I can see the merit of having them at the end from a historic BRL view.


therevills(Posted 2015) [#189]
I quite like the Go approach...

function update() 'lowercase so private
end

function Update() 'uppercase so public
end
No idea how protected would work though!


What about alternative case for protected? ;)
function UpDaTe() ' protected



impixi(Posted 2015) [#190]
My opinion:

* Default all class members to "private".
* Access specifiers should be prefixed.
* Do not include the ability to specify access in "blocks".
* Do not apply access specificity via case or character decoration.
* Allow only "public" and "protected" access specifier keywords.

If I had time I'd elaborate my thoughts on each point, but in summary the above will strike a nice balance between verbosity, readability and conforming to the relevant OOP principles, IMO.


marksibly(Posted 2015) [#191]
..or uppercase last letter?

function updatE() 'protected!

I'm still not 100% sold on protected. Well, protected fields anyway. I think these are a bad idea as they defeat the whole point of abstraction. About the only case that can be made for protected fields is that they're faster, but inlining solves that.

I really like the Qt approach where pretty much all virtual methods are protected, so you can't call them directly, eg:

Field matrix:Float[]   'private...
Field scissor:Float[]
 
Method Draw:Void()  'public
   PushMatrix
   PushScissor
   OnDraw
   PopScissor
   PopMatrix
End

Method onDraw:Void()    'private-ish. To make really private, use 'Final'...
   ...
End


Or better yet, a system where the base class calls the derived class, eg:

Method Draw:Void()
   PushMatrix
   PushScissor
   Derived.Draw
   PopScissor
   PopMatrix
End



Samah(Posted 2015) [#192]
@impixi: My opinion:

* Default all class members to "private".
* Access specifiers should be prefixed.
* Do not include the ability to specify access in "blocks".
* Do not apply access specificity via case or character decoration.
* Allow only "public" and "protected" access specifier keywords.

If I had time I'd elaborate my thoughts on each point, but in summary the above will strike a nice balance between verbosity, readability and conforming to the relevant OOP principles, IMO.

Agreed on all points.

@marksibly: ..or uppercase last letter?

I certainly hope that was a joke too. ;)

@marksibly: I'm still not 100% sold on protected. Well, protected fields anyway. I think these are a bad idea as they defeat the whole point of abstraction.

Possibly, but if it's simple to do I don't see any reason why you should exclude them from protected. People will just do whatever dirty hacks they want to anyway if they don't care about proper encapsulation.


dmaz(Posted 2015) [#193]
rant
personally, I'm not sold on private (and final for matter)...especially defaulting to it. I find far more value in protected. we need to remember that class users are programmers... In many case the class doesn't do or implement everything it can so as a programmer I'd like access to those things that make it work. over-privatization of classes have caused me more headaches than the opposite. In an large corporate development group with a lot of green programmers I tend to lean back towards more privates. But this language is not for large groups making oracle apps. At least with protected I still have access yet understand that these field and methods should be use with caution. now, we of course need private but I'm the opposite of say java programmers(no offense meant to anybody) and their everything private unless you know otherwise. IMO: a class writer should think and think hard about why he needs something private... it should not be just slapped on. inheritance gives us far more benefit than encapsulation. so, I don't have a problem with private, just how over used it's become in some places.
/rant

* default to public
* have protected
* only allow protected and private...

edit: and wouldn't it just be silly if the default method restriction was final?


ziggy(Posted 2015) [#194]
rant
personally, I'm not sold on private (and final for matter)...especially defaulting to it. I find far more value in protected. we need to remember that class users are programmers... In many case the class doesn't do or implement everything it can so as a programmer I'd like access to those things that make it work. over-privatization of classes have caused me more headaches than the opposite. In an large corporate development group with a lot of green programmers I tend to lean back towards more privates. But this language is not for large groups making oracle apps. At least with protected I still have access yet understand that these field and methods should be use with caution. now, we of course need private but I'm the opposite of say java programmers(no offense meant to anybody) and their everything private unless you know otherwise. IMO: a class writer should think and think hard about why he needs something private... it should not be just slapped on. inheritance gives us far more benefit than encapsulation. so, I don't have a problem with private, just how over used it's become in some places.
/rant

* default to public
* have protected
* only allow protected and private...

It looks like you prefer inheritance over composition. IMHO it is much better if the language directs people to the oposite http://en.wikipedia.org/wiki/Composition_over_inheritance so in my book, default to private makes much more sense.
edit: and wouldn't it just be silly if the default method restriction was final?

Well, for me it would be the perfect choice, basically because non virtual methods allow for faster execution and inheritance should be avoided when possible in favor of composition (based in interfaces with dependency injection if possible, to be even better). If it can't be avoided, it's better if it's implemented by the usage of interfaces, and if non interfaces based polymorphism is truly the best valid option after evaluating all the others, then, you can just make any method that fulfills the class contract and responsibility virtual, but this should be the latest choice for a worst case scenario.


impixi(Posted 2015) [#195]

IMHO it is much better if the language directs people to the oposite http://en.wikipedia.org/wiki/Composition_over_inheritance so in my book, default to private makes much more sense.



Good grief. That C# composition example makes me question the whole OOP paradigm. The following non-OO structured C equivalent seems more straight forward to me...



Oh well...

I wonder if it's too late to lobby for Mark to strip out all OO "features" from Monkey2? ;)


itto(Posted 2015) [#196]
@dmaz a class writer should think and think hard about why he needs something private


Perhaps the contrary? A class writer should think as hard as possible when making something public or protected, because that represent the interface of the class to the external world, and once you put it out, it becomes hard (if not impossible) to change the more time passes and the more people start using it (or you start using it yourself in your projects).

I'm not sure if it has been mentioned before, but a nice addition I'd like to see are read-only fields or properties.

class MyClass
    field aField:int readonly
end


I think it's handy and your code speaks more about how it's meant to be used. Here's their C# implementation.


Shinkiro1(Posted 2015) [#197]
Today OO often gets confused with proper programming. As any technique it's just there to help you manage complexity.
I am still for doing things the simplest way possible and if that means it is 1 function with 100 lines of code, because it's doing exactly 1 thing, I will not built an artificial structure around it which in fact makes it harder to maintain.

If anything we should be looking for paradigms that actually suite game programming, e.g. Data Oriented Design
OO encourages design that is not really performance friendly (cache misses)


Salmakis(Posted 2015) [#198]
>> That forces a specific naming style for Fields, Methods, Functions, and Properties. I don't like that.

>I didn't expect anyone would!

being beginner friendly was allways the cool Thing in brl languages, if you force new ppl to take care for case sensitivity so much this may not being a push towards the beginner friendly thingy


Gerry Quinn(Posted 2015) [#199]
I'm with dmaz, I like to use inheritance, and 'protected' makes extending a class easier without letting unrelated classes at your fields and methods. I tend not to use 'private'. If I'm not inheriting from the class, 'protected' is the same anyway.


dmaz(Posted 2015) [#200]
It looks like you prefer inheritance over composition.
actually no... I use both of these about equally... I don't like long inheritance chains but neither do I like fatter base classes or just components. I use each as I feel they are appropriate to the design of the application and I tend not to write in languages that makes that more difficult or annoying. (unless required)
and once you put it out, it becomes hard (if not impossible) to change the more time passes and the more people start using it (or you start using it yourself in your projects).
this... so now as the class user, I'm completely relying on the original programmer or hacking the class source (thus making that code part of my project) when I need new functionality.
If anything we should be looking for paradigms that actually suite game programming, e.g. Data Oriented Design
OO encourages design that is not really performance friendly (cache misses)
now, even given everything I complained about... this I think is right... but IMO, not at the expense of inheritance, composition and encapsulation


dmaz(Posted 2015) [#201]
basically because non virtual methods allow for faster execution
sure, but who needs those on of your code? the amount difference is negligible especially since you would still have the options for doing this where actually needed or wanted.

edit: man, I dislike web pagination!
(I seem to be really crabby these last 2 days)


GW_(Posted 2015) [#202]
basically because non virtual methods allow for faster execution

The difference is negligible between virtual and static method calls in modern cpu's.
See this and this

I'd like to clearly cast my vote that pre-pending member declarations with scope is just ugly imo. One of the major strengths of Bmax/Monkey is its clear and readable syntax.


Nobuyuki(Posted 2015) [#203]
@impixi

My opinion:

* Default all class members to "private".
* Access specifiers should be prefixed.
* Do not include the ability to specify access in "blocks".
* Do not apply access specificity via case or character decoration.
* Allow only "public" and "protected" access specifier keywords.



Absolute thumbs down from me on this one. VB.NET is very similar to this, private by default, requiring all access specifiers be prefixed when writing classes. It is a joyless experience full of boilerplate code that is rivaled perhaps only by Java. Which leads me to the next point....

@marksibly
I'm still not 100% sold on protected. Well, protected fields anyway. I think these are a bad idea as they defeat the whole point of abstraction. About the only case that can be made for protected fields is that they're faster, but inlining solves that.


Maybe I'm a noob when it comes to class design, or maybe I don't care about the "finer" merits of OOP and things like encapsulation, but I've found Protected to be fantastic for implementing a series of derived classes without copy-pasting or otherwise writing contrived code. The point (for me anyway) of using Protected is to have the flexibility of using multiple derived classes within a framework as if they shared Private internals -- allowing the classes meant for the more adventurous "end-programmer" to have exposed members should they decide to hack my code and make their own version, but otherwise keep them out of sight and mind for the ones who want the classes to "just work". Setting those members Private in these cases can require some annoying restructuring or busing between classes -- as a result, traditionally my Monkey code has defaulted to making these members Public, which makes them "less safe" for someone who doesn't know what they're doing. In addition, a good IDE can hide Protected members outside of its relevant context when performing autocomplete.

Again, I'm not sure if it makes for "good" class design in the traditional sense, but when working in a sufficiently advanced IDE, it is a pretty good tool that can be used to make code safer and easier to use, particularly for newbies who don't (or won't) dig into other people's classes.

Consider one (very recent) example that would probably best be made Protected but was instead made Public, because some people wanted to access it: Stack<T>.data[].

@dmaz
+1 to several of the things you've said.


marksibly(Posted 2015) [#204]
> Consider one (very recent) example that would probably best be made Protected but was instead made Public, because some people wanted to access it: Stack<T>.data[].

Actually, IMO this was exactly the right thing to do.

Adding a public Data() accessor means people can access the internal array directly (avoiding an expensive ToArray()) without any risk of putting the stack into an invalid state. And if we are going to allow access to the data array (either read only or read/write), why force people to jump through hoops to use it, ie: why should you have to extend stack just because you want to access the data array?!? This makes no sense to me!

If I had made the _data field protected as suggested by some people, then: a) it would have been a hassle for people to use easily and, b) the possibility arises that a derived class could change the array behind the stack's back, perhaps setting an array with length<_length which would lead to weird errors 'at some time later' at runtime.

Even if I did want to allow people to change the internal _data array, then IMO a public SetData method would be the right way to do it, so stack can make sure the array is big enough. By keeping _data and _length private, stack can guarantee it's always in a valid state, ie: that the 'invariant' _data.Length>=_length is always true.

But it's only really protected fields I have a problem with - having protected fields means an object can't guarantee consistent state (of those fields anyway), and locks down the design and implementation unnecessarily. By providing protected accessor methods to private fields instead, you can validate state, change field names/types if you feel like it etc.


Samah(Posted 2015) [#205]
@marksibly: why should you have to extend stack just because you want to access the data array?!?

Because we have to extend the class anyway if we want to sort. This is one of the reasons I made DiddyStack/DiddyList/DiddyDeque/DiddySet (although the last is unordered).
Also it allowed me to do cool stuff like stack.AddAll(list) to add all the elements from a list into a stack.
https://github.com/swoolcock/diddy/blob/master/src/diddy/diddystack.monkey

@marksibly: If I had made the _data field protected as suggested by some people, then: a) it would have been a hassle for people to use easily...

Which would have been a godsend when I designed the aforementioned classes. Instead I had to delegate method calls for each class.
Not really sure why you didn't give some kind of common interface on these...

@marksibly: But it's only really protected fields I have a problem with...

That doesn't mean they should be excluded from the language, if there are many developers who want it. You made this forum to find out what developers want! :)


Nobuyuki(Posted 2015) [#206]
I can see why _data was chosen to be Private, though I wanted to access it for the same reasons Samah did, and because it's part of the standard containers, extending it in as much a compatible way as possible was preferable to making a derived class which had to re-implement large parts of the code for alternative sorting / caching / etc., or simply not inheriting from the container at all and losing the convenience of the fast array access to be "backwards-compatible" with the standard Stack. Having an exposed property to access it safely is fine, too, in most cases.

I haven't looked at Diddy's source in ages, so I have no idea how Samah handled it. Of course if I designed the Stack class, the internal data would probably be accessible as a Protected member, danger be damned -- but that's only because in that specific instance where someone wants to "improve" the Stack class by extending it, they have an easier time doing it. Everyone else has to jump the artificial hurdle to access _data, which is supposed to serve as a bit of a warning to people in the first place that the field would normally been private...

Maybe it just boils down to a difference of opinions here on what sorta conveniences/inconveniences take priority when it comes down to it -- flexibility in being able to change the base class, or flexibility in being able to extend the derived class? I dunno..... Anyway, that was just one example of where I'd personally see Protected having use. In my own classes, I'd be using it in more places, since I see it as a convenient "in-between" scope that cuts away some of the fog that OO design patterns can sometimes put in my brain.


marksibly(Posted 2015) [#207]
> Because we have to extend the class anyway if we want to sort.

But Data() allows this...

Class MyStack<T> Extends Stack<T>
   Method Sort:Void()
     ArraySort<T>.Sort Data,0,Length
   End
End


My point here is not that Data shouldn't be exposed - it should have in the first place - but that it's possible to do it in a safe and convenient way via a simple public Data() method as opposed to exposing the actual _data variable via protected.

And, somewhat to my embarrassment, it appears Stack already has an undocumented Sort in there...


impixi(Posted 2015) [#208]
@Nobuyuki


VB.NET is very similar to this, private by default, requiring all access specifiers be prefixed when writing classes. It is a joyless experience full of boilerplate code that is rivaled perhaps only by Java.



One of the primary tenets of OOP is that of encapsulation. A relevant quote from that wikipedia article.


Encapsulation is the packing of data and functions into a single component. The features of encapsulation are supported using classes in most object-oriented programming languages, although other alternatives also exist. It allows selective hiding of properties and methods in an object by building an impenetrable wall to protect the code from accidental corruption.



By defaulting to "public" for class members, as Monkey 1 does, you break this "impenetrable wall" by default. It means you have to consciously plug those "holes in the wall" instead of having a solid wall to start with. And for what? A little less typing?


marksibly(Posted 2015) [#209]
> One of the primary tenets of OOP is that of encapsulation.

I think this is valid for fields, but not so much methods. 99% of fields will be private, while 90% of methods will be public.

And a class will always have SOME public members, while some classes may have no private members, so IMO public is a perfectly sensible 'default'.


GW_(Posted 2015) [#210]
so IMO public is a perfectly sensible 'default'

+1
If for no other reason, it's consistent with the other BRL languages.

By defaulting to "public" for class members, as Monkey 1 does, you break this "impenetrable wall" by default. It means you have to consciously plug those "holes in the wall" instead of having a solid wall to start with. And for what? A little less typing?

I don't get this logic. There are a lot of acceptable ways to do encapsulation without putting a burden on the 90% of programmers who don't want the enforced boilerplate.
Just type
private
after the class definition and be done with it if you want all your members private. I would hate to see everyone forced to declare public scope for everything every time they want it. Even the Java evangelists lament it's wordy boilerplate.


impixi(Posted 2015) [#211]
Well to be honest I don't care either way, because I think the whole OOP approach is "wordy"... But that's a "religious" debate for another time and place. ;)


Playniax(Posted 2015) [#212]
public is a perfectly sensible 'default'


Yup


Samah(Posted 2015) [#213]
Mark:
Last I checked, you have to extend the standard container classes and implement your own Compare method if it's a non-primitive generic. The Diddy container classes handle this for you by way of comparators/comparable.

Check out DiddyDeque to see the hacks I had to make for insert/delete that would have been way easier with direct access to the backing array.
https://github.com/swoolcock/diddy/blob/develop/src/diddy/diddydeque.monkey


Gerry Quinn(Posted 2015) [#214]
Mark said: " 99% of fields will be private, while 90% of methods will be public."

For you that's clearly the case. But some of us have considerably different ratios and methodologies.

It also depends how much you're writing for public consumption, instead of maybe writing something for yourself that you will likely extend further down the line.


marksibly(Posted 2015) [#215]
> For you that's clearly the case. But some of us have considerably different ratios and methodologies.

Well, it was a guesstimate based on not just my own code, but code I've seen in general. What would be your guesstimate?

Also, I consider the 'all classes have at least one public member' argument pretty compelling for defaulting to public.

> Check out DiddyDeque to see the hacks I had to make for insert/delete that would have been way easier with direct access to the backing array.

[edit]The best solution for this is for me to just fix Deque![/edit]


Nobuyuki(Posted 2015) [#216]
Being able to specify a standard generic comparator for containers so we can use quicksort/timsort or collate strings could be nice, too ;)

Edit: IIRC, comparators have been implemented separately 3 times: by samah, skn3, and myself. They're not completely interchangeable, but I wish they were! And of course, diddy has its own versions of most containers to implement things like quicksort. (Nothing like framework lock-in..) I imagine most issues would be solved giving access to container data arrays/nodes and/or just implementing comparators for standard containers...


ziggy(Posted 2015) [#217]
But it's only really protected fields I have a problem with
Yes, they're not useful. IMHO, if you need a protected field, something smells badly. In fact, protected methods are a bit smelly too to some, but somehow more acceptable.

Check out DiddyDeque to see the hacks I had to make for insert/delete that would have been way easier with direct access to the backing array.
Just my honest opinion. While I can see how it would have been useful, I would consider creating your own Queue by not extending Mark's one, and sharing a common interface with it.

If your implementation relies on the internal implementation details of a base class (that is, requiring the usage of an internal array), something's wrong! You're coding based on concretion instead of abstraction, and increasing dependency coupling, which is not nice if you're writing a framework to be used by other people.

I'm sure most, if not all people here, already know this, but if anyone else is interested or curious, this is quite nice dependency inversion explanation http://c2.com/cgi/wiki?DependencyInversionPrinciple


Nobuyuki(Posted 2015) [#218]
@ziggy

From the c2 article:
Some of this sounds like typical pro-OO procedural-bashing. The "device driver" examples may not extrapolate to all situations and assume that adding new devices is more common than adding new operations to existing devices. What is "rigid" often depends on assumed ChangePatterns. There is no free lunch in such cases, only estimations of paths of least costs. GoldPlating for "reuse" that is unlikely to happen in practice can often lead to unnecessarily complicated code (such as excess redirection).


I couldn't have said it better or more succinctly, even if I tried. So I'll let that quote speak for me. Lots of good stuff in those wiki pages.


Shinkiro1(Posted 2015) [#219]
In BMax you can pass your own sorting function, which I consider to be the best approach – no boilerplate, no implementation of interfaces, just give it a function with a certain signature and that's it. Sorting code doesn't need state so how is this even appropriate for a class. It's just a workaround for not having callback functions.

If MX2 has functions as first class values I think it will make a lot of things easier.

99% of fields will be private, while 90% of methods will be public.

I agree with the 2nd statement, but most of my fields are public. I generally only hide implementation details as private, if they are an attribute like position, scale or color they are public.

/rant
I am always confused when I see a Vector2D implementation where x and y are private. So they have their own properties because the implementation might change. Maybe later on you decide to play sounds everytime you access X() ...

Don't get me wrong, I find a lot of OOP principles useful. But every time I see people going to incredible lengths to fit their code into an OOP approved format I just cringe.
I know people that are unable to solve a problem other than first building elaborate structures of relationships between objects when they could have written 1 function. That would have been even more maintainable. More Code = more complexity.
/rant off

I just hope MX2 is not going in the direction of a purely OO language.

----
edit:
back 2 years ago I went to a job interview and as a test, they assigned me to program conways game of life in 1 hour. I hadn't done it before, so after reading the 4 rules ...

1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
2. Any live cell with two or three live neighbours lives on to the next generation.
3. Any live cell with more than three live neighbours dies, as if by overcrowding.
4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.


I started by building a Grid and Cell class. After some time had passed and I hadn't really gotten anything on the screen the programmer there interrupted me and said: "just use an array, no need to make things more complex than they are".

That was not only embarassing but really eye-opening as well.


dmaz(Posted 2015) [#220]
But it's only really protected fields I have a problem with[quote][quote]something smells badly.
I understand where you guys are coming from but I don't agree. These should be app design time decisions not the compiler's or language. (Doesn't obj-c make them protected by default?,of course that doesn't make it smart though... :)


ziggy(Posted 2015) [#221]
I understand where you guys are coming from but I don't agree. These should be app design time decisions not the compiler's or language.
We all agree AFAIK that those are architectural decisions (design time decisions). What I -and I think others- say is that it's hard to find a situation where a protected field is the appropriate decision. No matter what language you're using!

I started by building a Grid and Cell class. After some time had passed and I hadn't really gotten anything on the screen the programmer there interrupted me and said: "just use an array, no need to make things more complex than they are".
That's been fun to read. It was a very concise KISS example. Fun thing is, depending on which language you're using, arrays are objects too.


therevills(Posted 2015) [#222]
@Nobuyuki Nothing like framework lock-in..


Was that really needed!? Diddy is open source no one is locked into anything...


Samah(Posted 2015) [#223]
@Nobuyuki: And of course, diddy has its own versions of most containers to implement things like quicksort. (Nothing like framework lock-in..)

@Nobuyuki: I haven't looked at Diddy's source in ages

The quicksort functionality is a standalone module that was used by the old "collection" module. The new "container" module uses the stock Monkey sorting algorithms by simply calling Super.Sort().
Edit: There is a custom implemention in DiddyDeque since the official Deque does not support sorting at all. The developer is free to override SortItems() and implement their own, though.

@ziggy: Just my honest opinion. While I can see how it would have been useful, I would consider creating your own Queue by not extending Mark's one...

The point of extending the official classes is to make them usable with other frameworks.
@ziggy: ...and sharing a common interface with it.

The official classes do not implement any interfaces, which was another goal of the container module.


dmaz(Posted 2015) [#224]
say is that it's hard to find a situation where a protected field is the appropriate decision.
I was trying to point out that I favor protected where you would use private. as I mentioned, I don't like my classes all locked down. If someone is going to subclass, then that B should still be an A and have access as A would. Otherwise, as you pointed out, composition might be better suited. I'm an adult.... If I break your class that you left it open, that's my fault... don't close it because of that possibility.


Samah(Posted 2015) [#225]
To be honest I'm thinking we should just leave it as is. Monkey-X's implementation is fine, really. Since trans ignores newlines after Private/Protected/Public, we still have the option of explicitly defining the visibility of every member by putting the keyword before Method/Field/Function/Global/Class.
The only gotcha is that if you don't specify the visibility, it will use the most recent one. I think that's fine.
Public Field foo
Private Field bar
Protected Method Hello()
End

Is the same as:
Public
Field foo

Private
Field bar

Protected
Method Hello()
End



Gerry Quinn(Posted 2015) [#226]
I don't know what the stats in general are, but I tend to have most of my fields public (it is understood that they are generally considered read only) and the number of methods that are private depends on the kind of class - could be zero for a utility class such as Rectangle, or most of them for a game controlling class.

The bottom line is that everyone has a theory of what is right and what is a terrible sin against whatever programming religion they follow, but it's probably more important to pick a methodology you are comfortable with and be consistent.


impixi(Posted 2015) [#227]
@Shinkiro1
I believe Monkey comes with a version of Conway's Game of Life... ;)

These days I'd probably code it different.


Nobuyuki(Posted 2015) [#228]
@therevills
Was that really needed!? Diddy is open source no one is locked into anything...


No offense was intended. From what I've seen/heard in this thread, diddy's made great strides towards modularization and reducing interdependencies within the framework.


dmaz(Posted 2015) [#229]
have we talked about accessing vars in strings? like Print "x: $pos.x y: $pos.y z: $pos.z" so helpful and quick... formatting strings by addition sucks especially for long ones. if we have varargs I guess printf like function or actually printf would be sufficient.


Shinkiro1(Posted 2015) [#230]
@dmaz
Personally I think this looks more confusing than adding them together. Also if you allow variables, why not functions and method calls?
It's an inconsistency / special case I think is not worth it. The real problem might be not being able to specify string additions over multiple lines (it is in monkey1).

PHP allows it and I think it's horrible.


dmaz(Posted 2015) [#231]
I grown to like that from my early perl days and perl as a whole had really fantastic string handling. php was originally written in perl so that explains that. I do understand what you mean though and sure, scratch that. hopefully we'll get a full printf or something.


Nobuyuki(Posted 2015) [#232]
once again, I don't know what's wrong with using/writing your own String.Format() function.. swiss army knife functions like printf and perl/php's inline string formatting can be ugly to look at syntactically and are asking for escape sequence breaching if implemented language-wide, not to mention the potential overhead considering the fact strings are immutable...


dmaz(Posted 2015) [#233]
the language should be expressive but succinct. a butt load of double quotes inter-parsed with plus signs, variables and text does not look good and is way more charactery harder to follow than the example above, IMO. maybe I'm missing something but show me string.format() function (at least one that wasn't itself a varargs based sprintf) as elegant as inline building. perl string handling is far more powerful than any class I've seen. can it look complicated to some, sure but that's exactly because of it's power. I conceded the point above as this language shouldn't waist time with adding something like that when a simple (s)printf will do. and beside, the class implementation is going to be more overhead and tons of extra code than the function. Now, I'm not arguing that strings shouldn't be fully implemented classes... I'm fine with string.format(string,arg0,arg1,arg2...) or with extension methods and varargs, I'd be one happy camper :)


Danilo(Posted 2015) [#234]
Of course, line continuation at '.' makes sense for more operators, like '+', '-', etc....
shaderCode = "line 1" +
             "line 2" +
             "line 3"

A line-continuation operator is a must-have. VB uses ' _' (Space + Underline), but allowing certain (math) operators is more flexible.

Optional Arguments are already possible, so PrintF(z:String, a:Variant=0, b:Variant=0, c:Variant=0, d:Variant=0) is already possible,
but not as powerful as real VarArgs are.


DruggedBunny(Posted 2015) [#235]
shaderCode = "line 1" +
             "line 2" +
             "line 3"


I do like the idea of allowing operators to act as line continu... uh, -ators.


Samah(Posted 2015) [#236]
Diddy has a sprintf/format implementation:
https://github.com/swoolcock/diddy/blob/master/src/diddy/format.monkey


taumel(Posted 2015) [#237]
Hmm, could we change the way you define variables and stuff, like f.e. C# does?

Something like ... public float scrX, scrY ... instead of ... scrX : float, scrY : float ...

More elegant and easier to write.


JoshKlint(Posted 2015) [#238]
Whatever happens, I hope Mark realizes he should discard 90% of feature requests:




kmac(Posted 2015) [#239]
Not having made any requests in the past...my preference is for easy to use IO functions, like sprintf mentioned above. I've been diving into R recently and the ability to read and write data without headaches is the first step to being productive - at least for me.

I've only started watching https://www.youtube.com/watch?v=rX0ItVEVjHc but it seems that at least in part his concerns relate to input and output of data. Now that said, I'm primarily interested in text/CSV and so on.


Richard Betson(Posted 2015) [#240]
Whatever happens, I hope Mark realizes he should discard 90% of feature requests:

I think mojo2's architecture and structure are a good indication that there are no worries there. :)


Danilo(Posted 2015) [#241]
Could syntax for constant character literals possibly be made nicer, like in other languages?
' Many other languages

Select GetChar()
    Case 'a', 'A'
    Case 'z', 'Z'
    Case '+', '-', '*', '/'
EndSelect

' Monkey X

Select GetChar()
    Case "a"[0], "A"[0]
    Case "z"[0], "Z"[0]
    Case "+"[0], "-"[0], "*"[0], "/"[0]
EndSelect

' VB style, http://stackoverflow.com/questions/3374842/how-do-you-declare-a-char-literal-in-visual-basic-net

Select GetChar()
    Case "a"c, "A"c
    Case CChar("z"), CChar("Z")
    Case "+"c, "-"c, "*"c, "/"c
EndSelect

I like the first one most, but it's a problem because single-quotes start a comment in MonkeyX.

Would it be possible to add 'To' ranges for Case statements?
Select GetChar()
    Case 1 To 31
    Case "a"[0] To "z"[0]
    Case "0"[0] To "9"[0]
EndSelect


Could "EndSelect" get added, in spirit of If.. ElseIf / EndIf?


PixelPaladin(Posted 2015) [#242]
Monkey2 could use ' for single characters if comments would start with #.
This would make it possible to create a monkey based scripting language in the future which could use the '#!' shebang line at the beginning of documents.

#!/bin/monkey2
# monkey script

Function SomeFunction:Void()
    Select GetChar()
        Case 1 To 31
        Case 'a' To 'z'
        Case '0' To '9'
    End
End



Nobuyuki(Posted 2015) [#243]
more convenient Select Case syntax would be great. Ranges would be cool. Abbreviated syntax (similar to VB.NET's "Case Is") to have an operator would be great rather than the ridiculous "Select True" syntax that makes it no better than sequences of ElseIfs. Example:

Select chara
  Case 0  'Standard
  Case 1, 2  'Each arg is a separate case eval against chara
  Case 3 To 5 Step 1  'Similar to For syntax;  Step optional
  Case Is > 100   '"Is" is a stand-in for the variable being switch evaluated. This means...
  Case Is > 5 And Is < 100  '..that it can be used anywhere chara would be in a non-Select expression
  Default
End Select


Current String slicing syntax makes sense to me, but it didn't when I first picked up the language. Using single quotes for char literals won't make any more sense to a newbie, only to coders coming from languages that use this syntax. It would also bring that language's associated syntax baggage. Since we use ' exclusively for comments currently, I don't think it's a good idea. VB converts chars to their int representation with a function - it's way more verbose - but Monkey's is pretty decent, terse, and kinda makes sense in the context of slicing. Really at this point it'd just be changing one "special" behavior for another.

Edit: While we're at it, can we please remove the restriction that Step periods in For loops must be a constant at compile-time?


Danilo(Posted 2015) [#244]
Nobuyuki wrote:
Current String slicing syntax makes sense to me

I find the single-quote syntax is much easier/lighter on the eyes, and also for typing and better for health.
Case "+"[0], "-"[0], "*"[0], "/"[0]

Typing that with german keyboard:
<SHIFT+C> <a> <s> <e> <Space>
<SHIFT+2> <+> <SHIFT+2> <ALT-GR+8> <0> <ALT-GR+9> <,> <Space>
<SHIFT+2> <-> <SHIFT+2> <ALT-GR+8> <0> <ALT-GR+9> <,> <Space>
<SHIFT+2> <SHIFT++> <SHIFT+2> <ALT-GR+8> <0> <ALT-GR+9> <,> <Space>
<SHIFT+2> <SHIFT+7> <SHIFT+2> <ALT-GR+8> <0> <ALT-GR+9>

My fingers and wrist already hurt, but maybe I get used to the pain. ;)

It was only a question after all. If short and crisp char literals syntax can't be added, we continue to use string indexing instead.


ziggy(Posted 2015) [#245]
In case we can't use single quotes for char literals, I would love to have a char literal identifier, so we can avoid the "A"[0] syntax. Something like \A or @A or similar would do it.
If myString[0] = @A
instead of
If myString[0] = "A"[0]

We have $ for HEX notation of integers, we could have also a "char" notation of integers. C# and Java uses single quotes for this, which is very nice. In the other hand, vb.Net uses "char"c (notice the c after the second double quote, it's very nasty).


Nobuyuki(Posted 2015) [#246]
Local ascA:Int = %A  'Maybe?


Just how agnostic is Monkey supposed to be to document encoding, anyway? I imagine certain syntaxes could get hairy when using wide chars and trying to get an int value from them...


Danilo(Posted 2015) [#247]
'@' is pronounced 'At' and means the address of something. '@aol.com', '@twitter', '@variable'. In programming I read it 'at address' or 'AddressOf',
so 'If myString[0] = @A' looks really weird for character literals.

'%' is already used for binary numbers.
Local hex := $A
Print hex
Local bin := %10001101
Print bin


PixelPaladin's proposal looks good, but changing the comment delimiter would be a really huge change. Not sure Mark will like such a big change.

Some (currently) free signs:
^a^    ^a        ^ comment - usually read as 'power of'
°a°    °a        ° comment
#a#    #a        # comment
\a\    \a        \ comment
?a?    ?a        ? comment - question?
!a!    !a        ! comment!
§a§    §a        § comment
µaµ    µa        µ comment

                 ## comment
                 '' comment
                 // comment
                 /* comment */



Gerry Quinn(Posted 2015) [#248]
If you don't like the "A"[0] syntax, there's always the option of creating a table of consts like ASC_A, ASC_B, ASC_a etc. and just importing it. Pretty easy to read IMO.


Danilo(Posted 2015) [#249]
And ASC_ADDITION, ASC_MULTIPLICATION, ASC_SUBTRACTION, ASC_AT, ASC_PERCENT. Probably UNI_ for Unicode table. :)

String indexing and character literals are basically two different things.
Char literals have nothing to do with strings, they are not coupled. It's only MX where we use strings with indexing as a workaround for missing char literals.

I think it's recommended to add it to any programming language. If Mark doesn't find it useful, so be it. ;)


Nobuyuki(Posted 2015) [#250]
I personally think the workarounds are a janky solution to the real problem we're obfuscating here anyway. When you program in QWERTZ the lack of proper brackets in the primary plane winds up having you use more Greek than a gyro joint. Most Germans I know just use US-104 and be done with it, but that just goes towards the already existing bias programming languages have towards US English and our keyboards..


dmaz(Posted 2015) [#251]
Whatever happens, I hope Mark realizes he should discard 90% of feature requests:
then why is he making a new language?


dmaz(Posted 2015) [#252]
more convenient Select Case syntax would be great. Ranges would be cool.
bmx and monkey already support all but the "to" example.

so we can avoid the "A"[0] syntax. Something like \A or @A or similar ... We have $ for HEX notation of integers, we could have also a "char" notation of integers.
I like that idea...


ziggy(Posted 2015) [#253]
@Danilo
String indexing and character literals are basically two different things.
They're not when the compiler substitutes them with the integer equivalence at compile time, as Monkey does. So, in fact, it happens to be the same. It looks like you're accessing an array, but you're not. "A"[0] is converted to 65, etc. All in all, the problem is providing this functionality with a proper syntax.


ziggy(Posted 2015) [#254]
I hope Mark realizes he should discard 90% of feature requests
Which feature requests are not important? 90% of the discussion is basically formal. The features discussed are just, GC, Delegates (OO pointers if you want), C++ integration and... basically that's it! Then, there's been debate over how to express encapsulation, how to handle char literals, etc but those are not features per se, they're just formal settings.

For me, a non very well discussed feature request would be the debugger itself, some soft of unit testing support, and some sort of performance profiler. But no one seems to care too much for this requests.


JoshKlint(Posted 2015) [#255]
Because "too many features" is the leading killer of tech products, and core customers will happily request features with no regard to complexity, cost / benefit, and overall purpose of the product.


ziggy(Posted 2015) [#256]
Because "too many features" is the leading killer of tech products, and core customers will happily request features with no regard to complexity, cost / benefit, and overall purpose of the product.
Of course! Just that I don't think that's what's happening here. I see more of a formal debate from people more used to a C++ like syntax, or people more used to a more modern syntax (java-like, or c#-like, etc.) But if you pay close attention, it's basically a formal (and interesting) discussion about how the language should look like, instead of what features should it have. Fortunately!


DruggedBunny(Posted 2015) [#257]
I'm with Josh. As Henry Ford is reputed to have said, "If I had asked people what they wanted, they would have said faster horses."

Really looking forward to Monkey2, but, seriously, 80-90% of what's been discussed here I probably won't even touch!


taumel(Posted 2015) [#258]
I'm for throwing in ideas and collecting what's useful, obviously a very individual thing.

Less mostly is more but looking at Monkey i also see quite some room for improvements and now is the time to do it right.

As for Ford, somehow not the #1 in cars or horses anymore.


GW_(Posted 2015) [#259]
but, seriously, 80-90% of what's been discussed here I probably won't even touch

As someone who programs in Blitzmax full time for a living, My desire to include every bell and whistle of every other language out there is non existent.
There's very few new things that I want Monkey2 to include, but there are a few things it absolutely must have to be a productive replacement.
1. A debugger at least on par with Blitzmax, the current Monkey debugger just doesn't cut it. too much of the programs state is still hidden.
2. Pre-compiled modules. I think this already planned. Also if there was a way to leverage all the great modules already created for Blitzmax that would great.
3. A Gui library. (MaxGui conversion?) This is something you also hear all over the internet when when people are evangelizing/criticizing new languages.
4. A profiler, or at least a future plan for one. by that I mean a real stack-sampling profiler,. Right now It's nearly impossible to find your hotspots in Bmax and monkey programs.
5. Retain the Bmax/Monkey style core syntax of the language. (super important!)
6. Ability to generate Dll's
7. 64bit support for the desktop target and utilize the optimized code generation of gcc or llvm or clang.
8. Multithreading with be a huge plus for me.
With the exception of #3, notice that I didn't mention any libraries. max2d/mojo can be ported over, all of them can ported over eventually. The core language is the live or die part of it.
I might add that with nearly everything on that list, I don't require any of them to be present in version 1.0 as long are they are planned. I want Monkey2 to be the kind of language that I can use until retirement ;).
I wouldn't trade lamda's or list-expressions or automatic getters/setters for anything on that list above.
This isn't some wishlist I pulled out of my butt, This is what I consider to be the minimum for someone like me who makes there living programming in a BRL language.
I'm super excited for the future of this language. I trust Marks judgment and I'm ready help where I can to make M2 as awesome as I think it's gonna be.


Nobuyuki(Posted 2015) [#260]
@dmaz
bmx and monkey already support all but the "to" example.


I don't know about bmax, but Monkey most certainly does NOT support "Is" for more complex evals. You are correct that it supports comma delimited args, however. My mistake.

More on "Is": Conditions containing "Is" inside a Case statement which evaluate to "True" should trigger and short-circuit evaluation of other Cases in the Select block. (I wonder if there'd be any good argument to use Continue to allow switch fall-through? Basically the opposite of how C-style switch blocks work...)


dmaz(Posted 2015) [#261]
@Nobuyuki, it does support complex evals.
Local a:Int = 5
Local b:Int = a
Select True
	Case a>100 Print "a greater 100"
	Case a>5 And a<100 Print "a between"
	Case a=5 And b=a Print "a b = 5"
End



Nobuyuki(Posted 2015) [#262]
@dmaz
...
Abbreviated syntax (similar to VB.NET's "Case Is") to have an operator would be great rather than the ridiculous "Select True" syntax that makes it no better than sequences of ElseIfs.


Not sure how I could've emphasized that better so that it wasn't ignored..


Danilo(Posted 2015) [#263]
@dmaz:
Nice example (thanks!), but "Select True" seems to be completely undocumented. It's the first time I see this here.
Documentation shows only classical examples with "Select variable" and "Case 0, 1, 2, 3".
I expected "Select a"..."Case a>100 ", but that doesn't work - so "Select True" is a very nice trick.
For "Select True" I would have expected to evaluate to "Case 1" for example, but it seems to allow any [expression].

If this is official, could it be added to the documentation, please?

Help for 'Select' shows:
Select expression
    Case statements...
End Select
and should probably get changed to:
Select [expression]
    Case [expression]
End Select

And 'True' example syntax should be added to docs:
Select True
    Case [expression] ' can be any expression, like 'a > 100 And b=12'
End Select

Help for 'Case' is correct: "Case expression", but should add the 'Select True' example as well.

Could be confusing if docs say "Case statements..." on one help page and "Case expression" on another help page.


Gerry Quinn(Posted 2015) [#264]
IIRC, Select..Case gets transformed into a series of If statements, so it might be just a happy coincidence that it works.

Select x
Case 1
---> "if x == 1"

Select True
Case x > 5
---> "if true == x > 5"


Nobuyuki(Posted 2015) [#265]
What Gerry said is basically true from what I understand. There may be more going on there (I ran into a trans/monkey bug some versions ago when using case SELECT statements inside a generic class), but I don't think so.

the point of requesting the "is" syntax for case SELECT statements was to make it nicer to look at and less awkward compared to the Select True syntax. Using select true has no advantages over using a series of else if statements; all case expressions must then evaluate to either true or false and you don't get any easier to read (or type) code.

please excuse the strange formatting since I'm dictating this via voice commands from my phone...


Leo Santos(Posted 2015) [#266]
I'm fully aware 99% of the users would be against this, but I'll request it anyway! :-D
Is it too late (or too crazy) to ask for Python style code indentation (basically, get rid of all "End" keywords and just use tabs for indentation). It's so clean, compact and easy to read!

Something like this:
Class Layer
	
	Method Update:Void()
		If enabled
			For obj = Eachin rootList
				obj.Update()

	Method AddEntity:Void( ent:Entity )
		If ent.layer <> Null
			If ent.layer <> Self
				ent.layer.rootList.RemoveEach( ent )
				ent.layer.entities.RemoveEach( ent )
		rootList.AddLast( ent )
		entities.AddLast( ent )
		Game.entities.Add( name, ent )
	
	Method Draw:Void()
		If visible
			For obj = Eachin rootList
				obj.Draw()
	
	Method Reset:Void()
		For obj = Eachin rootList
			obj.Reset()

In this particular example, removing the "End" and "Next" lines reduces the code to almost half the original size!
Ok, ok, I'll go back to my hole now.

Leo.


taumel(Posted 2015) [#267]
I like it.

You want an editor with those sweet vertical dots/lines and of course your tabs are way too big, four characters are enough.


nullterm(Posted 2015) [#268]
No semi-colors, no brackets, no next/end. I'm in love!

That's what programming should be (to me). Not a series of punctuation and keywords for the sake of making like easier on the parser code. Minimalist: intent and whitespace, and that's it.


Leo Santos(Posted 2015) [#269]
You want an editor with those sweet vertical dots/lines and of course your tabs are way too big, four characters are enough.

Yes! The 8 space tab is how this forum translates tabs, I see it as 4 on my editor. And I use Sublime Text 3 (with the SubMonkey package), which has the sweet dotted vertical lines.

That's what programming should be (to me). Not a series of punctuation and keywords for the sake of making life easier on the parser

Agreed, but a lot of old-school programmers don't seem to like proper indentation, and this style requires everything to be properly indented. Personally I think it would be a plus, since it would force all source code written in Monkey to follow a readable standard! But hey, what do I know!


Samah(Posted 2015) [#270]
@Leo Santos: Is it too late (or too crazy) to ask for Python style code indentation...

No, no, no, and no. This is my pet peeve with Python, and would turn off just about every non-Python developer.

1) It's ugly.
2) Everyone has their own style and shouldn't be forced to use one they dislike.
3) Developers coming from any language other than Python will have to change their coding mindset.
4) It would be incompatible with Monkey X.
5) Wrapping code in begin-end blocks is much more intuitive for entry-level developers. There's a reason Visual Basic does this.

@Leo Santos: Agreed, but a lot of old-school programmers don't seem to like proper indentation...

Then those old-school programmers you have spoken with are terrible coders and should just give up.


taumel(Posted 2015) [#271]
@Leo Santos
Hah, Sublime here as well. :O)

As i wrote already, i like your suggestion, it looks decent, different and has a minimalism approach.

I don't understand people who want Monkey 2 to be an easy/familiar place for people who aren't using such products already. Entry devs will use Unity (because its known and due to its engine), Indie devs & smaller companies do use Unity (which is a 80% C# place), on OS X you can use Swift and so on. In my opinion just make it as easy and nice as you can, without caring about devs who just aren't around {yet}. A new version offers the opportunity to introduce new stuff and break with backwards compatibility (whipping up a convert macro/script shouldn't be hard too).


Leo Santos(Posted 2015) [#272]
Then those old-school programmers you have spoken with are terrible coders and should just give up.


Actually, I never talk to them! I just see them on the Internets, and I assume they're sweaty, smelly dudes with long white beards and that they spit when they talk, so I stay away from them!

I'm glad you do too! ;-)


Gerry Quinn(Posted 2015) [#273]
I find Python-style indentation syntax quite horrific. I would go so far as to say it would render a language unusable for me.


degac(Posted 2015) [#274]
Personally, I think MX2 (or well, any language) should be 'easy' to write/type and to read: using tabulation like in Python (to me) is a very bad idea.
So if you want use End as 'closing' or End Method, or EndMethod etc. - and don't use strange characters like {} (they depends on the keyboard you are using...)
BRL's languages have a nice story about syntax, I don't see any reason to complicate things that works (quite well).
IMO MX2 should check what the other languages have (and what is really useful) and try to implement it in BRL-style.


taumel(Posted 2015) [#275]
When you're coding, you're (or the editor is) adding tabs for you anway, so, the code is there already.
Having to use curly braces or end or even worse specific end statements is redundant and feels more like the semicolons you want to get rid of too. Nicer readable code on less space.


Danilo(Posted 2015) [#276]
I don't use TABs, because they are displayed differently in any editor. Any editor I use replaces a TAB with 4 spaces for me (after setting this personal preferences),
but that may be very different for other users. Indention-dependent syntax is one of the worst things ever invented.


taumel(Posted 2015) [#277]
When i was looking for a new crossy text editor years ago, all those, which were more interesting, offered an option to set up a tab/spaces ratio in the prefs.


Samah(Posted 2015) [#278]
Thankfully, you will never convince Mark to clone Python's awful syntax. If it made its way into Monkey 2, I would instantly revoke my Patreon. :P


taumel(Posted 2015) [#279]
Might be the case, but it's a rather weak argument for or against such a feature, don't you think?


Danilo(Posted 2015) [#280]
I will never ever participate in the patreon stuff, if indention-dependent syntax gets added.
One of the reasons I'm waiting for the first release before spending any money on the project....
...because I'm not 100% sure about the final outcome, yet.
Looks good so far generally, but some feature requests are really worse and ugly.
I don't want to contribute to and use such an ugly thing, so I'm better waiting for something to try out..


taumel(Posted 2015) [#281]
Fair enough but i think if everyone would think this way (i only pledge if i get xyz) things would be way more complicate. On the bright side patreon offers you shades of gray, like defining the amount you want to pledge and being able to cancel your pledge each month. I guess some of us are here for the same but then again for different reasons as well.

Thinking about it, i've coded in C64 Basic, 68k Assembly, GFA Basic, ARexx, Fortan, Cobol, Eiffel, Erlang, Lisp, Smalltalk, C, C++, Lingo, BlitzMax, Action-/XYZscript, PHP, Ruby, PPC-Assembly, Objective C, Swift, C#, some visual tools (like in Virtools/Unreal/...), a little bit in Monkey and ... dunno. Some of these languages are built on very different concepts, still they can be great (others suck from the start till the end).

If you were able to grok one language, you should be able to learn another one too. Monkey 2 should be Monkey 2 but not 5% Visual Basic, 10% Monkey, ... just because some are familiar with those, let the best ideas/concepts win instead.


Samah(Posted 2015) [#282]
Monkey 2 should be Monkey 1 with more features. I see no reason to significantly change the existing syntax.


Danilo(Posted 2015) [#283]
@taumel:
Of course, Mark can add any weird features he likes to add. After that general decisions, everybody decides for himself/herself
if he/she wants to support the project using Patreon. I don't give a cent to a project I don't like. That's a premise.
Why should I give ANY money to a project I don't like? Doesn't make sense...


ziggy(Posted 2015) [#284]
God no, indentation defining code blocks introduces lots of issues when teamworking and people start mixing tab-to-spaces conversion editors, etc.


taumel(Posted 2015) [#285]
@Danilo
Sure but sometimes you need to invest, so that something might happen, without knowing if it will turn out into something good or bad, or just look at it as crazy money, might also be just a few bucks. Anyway i get your point.


Danilo(Posted 2015) [#286]
I am pleased to confirm my agreement.


nullterm(Posted 2015) [#287]
For the record, I don't think Mark should make MX2 use tabs instead of End/Next.

But I am totally hoping I can do some python custom build phase to allow me to. ;)


marksibly(Posted 2015) [#288]
I actually really like python's indenting style. I do find it looks a little 'unbalanced' in a way, like the code is about to 'fall over' or something, but I suspect that's just my inexperience with it.

The compiler could error out on non-tab whitespace at the start of a line to prevent formatting errors (ie: you HAVE to indent with tabs), so it's theoretically doable.

But, I think it's probably a bit 'far out' for monkey2 - it'd likely put off a big chunk of existing users, and would inflict a fair amount of pain on people converting stuff.

So nice idea, but not for monkey2.


taumel(Posted 2015) [#289]
How do you come to the conclusion that it would put off a big chunk of existing users?

Gut feeling, backed by feedback (apart from the few people posting here), ...?

The way i understand BRL's languages is making things easier, less annoying for hobbyists and smaller pros. That's why (and due to Basic's history) there are ENDs instead of curly braces (and before that there were END XZY). Now no ENDs is even easier, compact and less to type, so ...


marksibly(Posted 2015) [#290]
Call it 'programmers intuition'...

It's just too radical a change, more suited to 'zebra1' than 'monkey2'!

Perhaps if I felt more strongly about it, but I don't.


taumel(Posted 2015) [#291]
Can i help funding Zebra (sounds even better than Monkey)? ;O)

Well, maybe you want to reconsider your position. I think it would be a very nice feature, especially for people who are into how code looks like in a minimalistic way.

Anyway, thanks for your feedback.


skape(Posted 2015) [#292]
I love Python style blocks. I do think it would be off-putting to quite some people though! At least "end" is better than braces in most cases, IMO...


taumel(Posted 2015) [#293]
But "at least" is a little bit boring for giving birth to a new language, isn't it?!

It might look confusing on a first view, like something is missing, but once you get used to it, it's great.

It also could add to a new and cleaner look in Monkey 2.

End Function/... -> End ->

I suggest thinking about this some more time and staring at code.

At least (another one ;O) we could replace the "End" with a "."

It wouldn't be as pure anymore but still more elegant than those rather old skool Ends.


MikeHart(Posted 2015) [#294]
Marc, is it possible to give the supporters an overview how Monkey2 will look like now? You got a lot of suggestions and back then you said it you would have something to show within a month which is already gone by now. Would be cool if we can see what you are up to. Not in a running app, but general syntax features, stuff like that.


marksibly(Posted 2015) [#295]
I'll be doing a semi-major 'progress report' post tomorrow.

There's still nothing to release yet sorry (I'll explain why...) but things are definitely getting interesting/exciting!


Gerry Quinn(Posted 2015) [#296]
The thing with Python's indentation syntax is that not only do a lot of people hate it, those who hate it hate it a LOT!


Richard Betson(Posted 2015) [#297]
but things are definitely getting interesting/exciting!

Shock and awe me. :D


PixelPaladin(Posted 2015) [#298]
I really like python and use it a lot - but with language features like this it would be even harder to call monkey a basic like language.
In my opinion the 'End' should stay. But there are other things in python that could be useful. For example the library imports: in python it is possible to import just one or just a few functions or classes from a library.

From os Import LoadString, SaveString


Maybe this could even lead to faster compile times - I'm not sure.

The ability to import libraries from everywhere in the code would be nice, too. But I think this would slow down the compile process …

Function Foo()
    From os Import LoadString
    …
End



taumel(Posted 2015) [#299]
Why would it be a problem if Monkey 2 ends up being no/less Basic?

What you want is a cool, new, focused, easy to use, elegant and powerful language. It should be really good because it will take some time until it will be finished and from there on hopefully last for a couple of years. Currently there are number of languages popping up left and right, some have a small user base, others some serious steam behind. You really don't want "it's like Basic" being your main selling point then.

I want Mark to dare Zebra with Monkey 2, it sounds more exciting and competitive in the long run and i'm sure, apart from a few "but i need to convert xyz" minded people (they'll adapt after some more time) the audience would appreciate such efforts, as its fun using something new which is well done and makes click.

Breaking with conventions when you have something better instead can be such a relief and increase the motivation on both sides. A reasonable degree of this user base also is getting older, so bring up the cool stuff now, not in ten years.


therevills(Posted 2015) [#300]
-1 for Python's indenting style... hate it.... if I wanted to use it I would program in Python...

I would prefer to code in Shell (which I hate too), with its "FI"s, "ESAC"s and "ELIF"s....


degac(Posted 2015) [#301]
@Taumel:

If Mark wants to create its own language, with all the features he want to introduce, he is free to do it, none can stop him.
But if you want that the language created by Mark is used by other users, you need to 'meet' the market.
Mark could create a sort of meta-asm language full with strange symbols and definitions, or just a console-text language with no-gfx and no-sound support, but I really doubt that there will be many followers...


Dabz(Posted 2015) [#302]
Any news on the semi major news update malarkey then? :D

I've been nailed to me phone the last two days waiting! ;)

Dabz


taumel(Posted 2015) [#303]
In my opinion 3 aspects were relevant for the so far success of BRL products:


a) The easiness of the language
Historically Basic offered some kind of easiness which allowed hobbyists to grasp code easier or allowed pros to move faster forward (may it be prototyping, internal tools or real products). But this easiness Basic once was representing is nowadays part of many languages and some of them surpassed Basic years ago already. So, the benchmark isn't Basic anymore, it's the idea behind Basic you're interested in. If you code a few lines in different languages you can see this pretty well. Therefore i'm not into Basic but the best possible solution to express this easiness.

Secondly most of us aren't absolute beginners anymore which allows Mark to introduce more advanced concepts to the language too. You don't have to use them but you can. Speed is another key factor as speed always matters.


b) Engines' capabilities
An adorable language is useless unless you can't output something as well, so, having easy and again fast access to video and audio components is important (as well as working input ;O). BlitzMax was awesome in this respect for 2D. It made things easy whilst hiding a lot of the ugly stuff from the user. Today you also want a 3D engine under your fingernails, i'm sorry but that's just the way it is.


c) An easier market.
Competitive products often were either buggy and bloated, too slow or too expensive. It also was less knowledge/resources needed to place a competitive product on the market. Mark's generous license and cheap pricing also was a plus. So, Mark tries to focus already (less platforms, no 3D engine *snief*, if there won't be someone else adding something good, that's quite a bummer for Monkey 2 because 3D is still hip and offers a real benefit over 2D in many use cases).

With mojoX Mark will probably write his own 2D/... module, sound related, in another thread Skn3 made a few suggestions already. Sound needs to be enhanced badly. After you've used Unity 5's audio engine, back in Monkey, you feel like being thrown back into the stone age. You won't be able to impress many users this way.

:

Anyway what i was trying to say is that Basic's syntax is irrelevant. It's just about the accessibility, how easy and fast (and for the connoisseurs, how elegant) can you get something done, and i'm sure a large percentage of the Blitz crowd thinks the same way and people outside of the Blitz/monkey community couldn't care less about Basic anyway.


Nobuyuki(Posted 2015) [#304]
Anyway what i was trying to say is that Basic's syntax is irrelevant. It's just about the accessibility, how easy and fast (and for the connoisseurs, how elegant) can you get something done, and i'm sure a large percentage of the Blitz crowd thinks the same way and people outside of the Blitz/monkey community couldn't care less about Basic anyway.


Perhaps. But if it's only about the accessibility, then people would just as easily use some other tool. I came to Monkey after many years because I felt it maintained a spirit I hadn't seen since BASIC was in its heyday. To me, Python just isn't the same. But to many newer coders, Python is great. And, for the majority of people these days, if they want to get something prototyped rapidly, they'll just use Python. Or, for games, a more complete system like GameMaker or Unity. Nothing you said IMHO would set Monkey apart from those, so I don't see the justification in attempting to dump all of the "labor points" into some nebulous definition of what's easy, fast, or elegant by the current fads of the day. I personally feel like it should remain a bit visionary, and I'll expand on why below.

Now, personally, I just don't see Python doing all of the things a quality BASIC was able to do many years ago before it fell out of favor with the coding elite. These days, however, Python is a much more modern and appropriate language, and it does a better job at rapid prototyping in a modern environment than most dialects of BASIC can currently do. The BASIC languages which may arguably do better at rapid prototyping than Python are crippled by their commercial nature. So, I believe there is something to prove with BASIC -- there's an underexploited niche for a BASIC-like language where people can be made to care. What makes something a BASIC dialect over something else is debatable, but I think everyone can agree that "english-like" syntax is a big part of it. That was one of its primary design intentions, as well as high-level portability. Monkey really does carry this torch, and I think to completely abandon this philosophy would also abandon a part of what makes the Blitz line of languages special in this day and age.

I believe Mark understands this, which is why I put some faith into the notion that he's not going to abandon that philosophy entirely. That's also why I think the language should remain "visionary", because if we decide to adopt whatever common wisdom says is most accessible, fast, and elegant at the time, we'll basically get something which is not much different than what already exists, and we definitely won't get anything that will convince anyone to give it a look when the languages it takes cues from are already far more established (and are still in common use).


Samah(Posted 2015) [#305]
@Nobuyuki: *wall of text*

Well put.

Out of curiosity, what kind of "prototyping" do you mean? For a really simple script I might fire up SciTE and the Lua interpreter.


Nobuyuki(Posted 2015) [#306]
Out of curiosity, what kind of "prototyping" do you mean? For a really simple script I might fire up SciTE and the Lua interpreter.


A few things people use Python for rapid prototyping for are commandline tools which utilize some of its built in libraries (something Mojo could do for certain things like audio or graphics, but doesn't -- that's okay in most cases, but it IS something Python's libs can do), and I've heard that others have used its immediate mode for simple calculations and quick loops and such. I haven't had a need for an immediate mode interpreter since I was a kid, but I'm sure some people benefit from one. Many years back I was able to piece together bindings to libmodplug and pass the output to Python's wav lib to make a wave writer for mod files; something I don't think I would've had the skills or knowledge to do in any other language at the time. Just things like that.


taumel(Posted 2015) [#307]
Well, such an approach a.o. could help, bringing it more back into the game and making it more enjoyable for yourself, so that you want to spend your time with it.

I have no nostalgia for Basic because it never offered something special to me. I've programmed in easier, and more "english-like" languages before (Max). Due to that i'm german expect me to favour a more german like language then too. BlitzMax was cool because it offered this nice balance of an easy to use language but where the language also was able to use the engines being attached in an easy way (if needed you could add some more), and so you could achieve stuff.

Some other, better, languages often lack this tight working together connection, so, they can be a pain to get something easily and quickly done. Whipping up some code? Easy, done. But getting this to actually do the wanted the stuff on the screen? Can be a painful experience. Ergo: Sweet language in combination with other components, often offer a unbalanced experience.

See, i guess quite some people want code a few lines (the easier/elegant/less bloated/powerful, the better, but with this code they also want to achieve something, express themselves). A better language where Basic isn't in the way just for nostalgia can only lead to better results. Basic is from 1964. It's also not the same anymore but i'm sure if Kemeny and Kurtz would be good language designers they would come up with something different today. As i wrote already, you want the nail the idea behind Basic but not Basic.

What i don't understand about some of the more hardcore fans here is. Mark practically already went out of business due to the design goals he had for Monkey (which quite some praised here). And now you're kind of doing the same thing again. When i read certain suggestions or opinions here, i sometimes have to think: Jesus, this guy might be a somehow capable programmer but he must be either rather young or lacks a better understanding for future trends, possible commercial consequences, ...

Looking at Patreon, so far Mark primary gets money from old skoolers and i don't know how open he thinks his audience really is. According to his last statement i guess he thinks we're more conservatives. We could find out if this is true by various feedback sessions. It also might be true that some people say "Nah, i want it more like Basic ." but i'm sure that when they would be confronted with something new and better, also giving them some time to get used to it, they would give it a fair chance and afterwards they might like the new stuff and the Basic nostalgia would be gone due all the possible improvements they now can enjoy.

So, i'm all in for trying to make the best programming language right now and against dropping great ideas just because they might be too advanced due to Basic or stuff. Life is too short to work on things which don't feel right.


taumel(Posted 2015) [#308]
Well such a approaches could help, bringing it more back into the game again.

I have no nostalgia for Basic because it never offered something special to me. I've programmed in easier, and more "english-like" languages before. Due to that i'm german expect me to favour a more german language then too. BlitzMax was cool because it offered this nice balance of an easy to use language but where the language also was able to use the engines being attached and add some more in an easy way and so you could easily achieve stuff.

Some other better languages often lack this tight working together connection, so, they can be a pain to get something easily and performant done. Whipping up some code? Easy, done but getting this to do something on the screen? A painful experience. Ergo: Language in combination with other components, not a convincing bunch of tech anymore.

See, i guess quite some people want code a few lines (the easier/elegant/less bloated/powerful, the better, but with this code they also want to achieve something, express themselves). A better language where Basic isn't in the way just for nostalgia can only lead to better results, Basic, dude is from 1964, it's not the same anymore but i'm sure if being good enough language designers both Kemeny and Kurtz would come up with something different today.

What i don't understand about some of the more hardcore fans here is. Mark practically already went out of business due to the design goals he had for Monkey (which many praised here). And now you're kind of doing the same thing again. When i read certain suggestions or opinions here i sometimes had to think, jesus, this guy might be a somehow capable programmer but he must be young or lacks understanding for future trends, possible commercial consequences, ...

Looking at Patreon, Mark gets primary money from old skoolers and i don't know how open he thinks his audience really is, according to his last statement i guess he thinks we're more conservatives. We could find this out by various feedback sessions and it might be that quite some people say "I want it more Basic like." but i'm sure that when they would be confronted with something new and better, also giving it some time to get used to it, afterwards they also would dig it and the Basic nostalgia would be gone due all the possible improvements which could have been made.

So, i'm all in for trying to make the best programming language right now and am against dropping great ideas just because they might be too advanced for nostalgia. Life is too short for working on stuff which doesn't feel right.


dmaz(Posted 2015) [#309]
[edit]reiterating what taumel just said :)[/edit]
The term "Basic" has a stigma to very many and I think it's bad marketing and something we should not embrace.

The reason I've use Mark's products for so long as they've just felt comfortable to code in for the 'time' and they accomplished a LOT in small packages. In other words, syntax is important but not as important as the features that help you quickly write good stuff with great performance. i.e: easy and fast development.

There are many languages and development systems... the important question is why would somebody want to use monkey 2 over any of those? What could be a draw for monkey2?

I think the biggest is language features that promote game development and performance. but still with basic feature that allow utilities and simple applications. Lets face it, most applications are better done with languages that have good support for large application frameworks like .net. because that's what they focus on.

I've used lots of different languages for hobby and professional work non have been python though. I liked the look of the code in the example a few pages back being so succinct. But was completely against the idea for monkey2. The thing I didn't like was the idea that I'm required to use white space a specific way which made me think of cobol. Something I had to use for a year, and it sucked. But, this link somehow started to change my mind on python: http://www.secnetix.de/olli/Python/block_indentation.hawk

BUT, I like to use tabs! now, I think the lexer should be able to accommodate tabs and spaces by just knowing the tab size and turning them into spaces. Of course your code would break if you changed tabsize or another coder added code at a different size so that wouldn't work. I would be happy if the lexer just required a standard tabsize. I don't use tabs to change another coders whitespace to my liking, I use tabs for quick keyboard movement and manipulation. so a standardized size works for me. So I think I've come around to that python example above. I'm really starting to like it.

[edit]I missed this quote from Mark saying an option would be to require indenting with tabs. And I think that basic change would make monkey2 stand out to a new crowd and is really not that bad for the old.[/edit]

But I think we need other things as well...
I doubt Mark can or even wants to make an totally integrated development environment like Unity or Gamemaker. But is it possible to substitute some of those conveniences with the language? I think it is... but that's a different post.


Nobuyuki(Posted 2015) [#310]
What I'm hearing is that people want to have what essentially the goals of BASIC are, but without having it be BASIC. Stigmas on names are for superstitious people, so I hope we're not miscommunicating based on mere semantics here :)

I'll be the first to say that I'm not sure if my nostalgia blinds me to other languages which are perfect for filling the niche BASIC once had in today's environment. I feel that perhaps a Ruby or Python fills this niche, and yet, I don't have the same joy and ease coding with them than I do with Monkey, or even VB.NET (as much of a mess that's become). It's not a simple issue to succinctly articulate, but it definitely has nothing to do with BASIC's "taboo" reputation or Monkey's syntactical heritage. The thought that this would get in the way of advancing the language seems a bit like a strawman... Progress isn't mutually exclusive with keeping the syntax "BASIC-like", that sorta moniker (no pun intended) for a language family is open to a wide amount of interpretation, especially one which arguably has only one "truly" modern variant.


taumel(Posted 2015) [#311]
Mark could add this feature without too much fuzz, we're still at the beginning of V0.x

If it annoys too many people, he could remove it again or make it an option (although this might end being a mess when mixing code).

I want it, i mean the feature, not the mess.


Tibit(Posted 2015) [#312]
Curious about null, made me think about this talk: Null-References The Billion Dollar Mistake Tony Hoare

Is not Null like having an enum forcibly attached to each object? Would it make more sense to have the user explicitly define extra states (such as null)?

Optionals
'-- If null did not exist --
Class Door Extends Entity Implements IDoor
      Enum DoorState Open, Closed, Broken End
      Field is:DoorState = DoorState.Open
End

Local door:= new Door
If door.is.Open
      print "open"
End

Local myDoor:Door ' Compile error, have to be a door, and this would implicitly make it null

Local myDoor:= MyDoorCreationFunction() ' Works fine, since this function cannot return null

Local myDoor:= MyMaybeDoorCreationFuntion() ' Compile error, since function might return null

No need for null check statements in code.

BreakDoor(myDoor) 'Access without worry!

However sometimes me might really need null, so what about Class-States?

'-- Having custom states, even for null --
Class Door Extends Entity Implements IDoor is Open | Closed | Broken | Null ' *not sure about syntax
      Field ID:int
End

Local door:= new Door
If door is Open or Broken
      print "You can enter!"
End

Local myDoor:Door ' Works fine since null is a class state

BreakDoor(myDoor)

Function BreakDoor(door:Door)
      if door
            Print "Door is now broken"
            door = Broken
      else
          'handle null scenario
      end
End

Do not really have any argument for or against, just feels like a good idea when "modelling" game objects. Curious to hear what others think!



Leo Santos(Posted 2015) [#313]
Ok, here's another (hopefully less controversial) suggestion. I don't know how this feature is called, maybe someone can enlighten me.
Suppose you could (optionally) write the name of a function's arguments next to it, so it is clear to someone reading a source code what each argument does.

So this line, which is not self explanatory without taking some time to look at the function definition (and even then doesn't read very well):

Rendering.Setup( 320, 240, 60, True, True, 16.0/9.0 )


Would become this:
Rendering.Setup(	width = 320,
			height = 240,
			framerate = 60,
			renderToTexture = True,
			enforceAspectRatio = True,
			aspectRatio = 16.0/9.0 )

The idea here is to make the code more clear to the reader, although it is also more verbose. Another possible benefit is that you can pass the arguments in any order, since they're named.
Cheers.


Danilo(Posted 2015) [#314]
@Leo Santos:
Named Parameter / Named Argument
- https://en.wikipedia.org/wiki/Named_parameter
- https://msdn.microsoft.com/en-us/library/dd264739.aspx


Tibit(Posted 2015) [#315]
I enjoy named arguments a lot from javascript, I find it adds a lot of clarity around a function-calls intended purpose. Especially in libraries or when sharing code with others.


PixelPaladin(Posted 2015) [#316]
Named parameters can also simplify the usage of optional parameters:

Function DrawImage : Int ( image:Image, x:Float, y:Float, rotation:Float=0.0, scaleX:Float=1.0, scaleY:Float=1.0, frame:Int=0 )
    ...
End

DrawImage(myImage, 0, 0, scaleY = 2.0) 


In this case we no longer need to specify optional parameters we do not need.

Unfortunately there seems to be one major problem with this feature in monkey:

Function DrawImage : Int ( image:Image, x:Float, y:Float, frame:Int=0 )
    ...
End

Function DrawImage : Int ( image:Image, x:Float, y:Float, rotation:Float=0.0, scaleX:Float=1.0, scaleY:Float=1.0, frame:Int=0 )
    ...
End

DrawImage(myImage, 0, 0, frame = 3) 


This is not possible because there are two functions which could be meant.
In python (which has named parameters) the second function would replace the first one:

def draw_image ( image, x, y, frame:Int=0 ):
    ...

def draw_image ( image, x, y, rotation=0.0, scaleX=1.0, scaleY=1.0, frame:Int=0 ):
    ...

# only one function with the name 'draw_image' exists

draw_image(myImage, 0, 0, frame = 3) # this works



Samah(Posted 2015) [#317]
@PixelPaladin: This is not possible because there are two functions which could be meant.

Your DrawImage example is really just poor design. There's no reason to have that first definition anyway. If you really wanted to do that, just give them different names. We already have the incredibly annoying restriction that you can't overload an inherited method.

@PixelPaladin: In python (which has named parameters) the second function would replace the first one:

Python doesn't support method overloading? That's disappointing...


nullterm(Posted 2015) [#318]
@Samah, no, one method per name. It's a disadvantage, but the benefits of the Python language on the whole outweigh the disadvantage. You can though get around that with optional parameters or RTTI like code.




PixelPaladin(Posted 2015) [#319]
@Samah: Your DrawImage example is really just poor design.

Well - it was just an example to show that named parameters and function overloading does not really fit together and can cause problems (I am sure there is some function Foo(x, y=23, z=42) where this example makes more sense). But if we could find a way to get both features without having these problems this would be really great.