View Full Version : Concept: Context function
Petr Schreiber
18-11-2015, 17:56
Before I try to demonstrate "how", have a look at this:
if fileCreationDate > 1.Hour.Ago then
' do something
end if
Reads great, right? And it could be built in to language with support for "context functions". What would that mean?
In case thinBasic would find construction like:
variable.something, it would of course do the usual checks for UDT members, but if it would not find any member named something, it would also check, whether there is a function, which takes TypeOf(variable) as first parameter with name something, and it would pass that variable as the parameter then. And it would work in chained way.
So for the example, all you would need to do to implement the above:
Function Hour( nValue as Number ) As Number
' -- Converts nValue to amount of milliseconds
End Function
Function Ago( timeInMilliseconds as Number ) As Number
' -- Subtracts the timeInMilliseconds from Now and returns again timeInMilliseconds
End Function
...you could call these directly:
Number oneHourAgoInMilliseconds = Ago(Hour(1))
...but also via the syntax proposed - because the parameter would be propagated via the "dot pipeline", not via parenthesis.
This is not needed within TYPEs usually, as we can define custom functions now (big THANKS to Eros), but with primitive types, such as Numbers and Strings, there is no way to "expand them".
Do you like this idea? What do you think about it?
As with all the great ideas - this is not something I invented, I saw the 1.hour.ago syntax in Ruby, and liked it very much.
Petr
ReneMiner
18-11-2015, 18:44
This would work only for functions that have 1. parameter passed ByRef...
We also could stay on current syntax and do it like this:
Function String.Unquoted([parameters]) As String
Function = Remove$( $DQ, Me)
End Function
Function String.Uppercase() As String
Function = UCase$(Me)
End Function
' Function String.Length() As Long
' Function = StrPtrLen(StrPtr(Me))
' End Function
String s = $DQ & "hello this is a quoted string" & $DQ
PrintL s
PrintL s.Unquoted
PrintL s.UpperCase
' PrintL Str$(s.Length)
' now what if this:
PrintL s.Unquoted.Uppercase
PrintL Str$( s.Unquoted.Lenght ) ' thinkeable...???
' ---???---???---???---???---???---???---
' equals this:
Function Unquoted(ByRef s As String[,Parameters]) As String
Function = Remove$( $DQ, s)
End Function
Function UpperCase(ByRef s As String) As String
Function = Ucase$(s)
End Function
String s = $DQ & "hello this is a quoted string" & $DQ
PrintL s
PrintL Unquoted(s)
PrintL Uppercase(s)
' PrintL Uppercase(Unquoted(s)) ' ???
' ... nay ... not ByRef i think since we have to refer a variable
' ... ... ... ... ... maybe allows later:
Type tFace
X As Double
Y As Double
Z As Double
col as TBGL_tRGBA ' this is a MODULES TYPE !!!
End Type
Function TBGL_tRGBA.SetValue(Byval R As Byte, Byval G As Byte, Byval B As Byte, Byval A As Byte)
Me.R = R
Me.G = G
Me.B = B
Me.A = A
End Function
Function TBGL_tRGBA.UseToDraw()
TBGL_Color Me.R, Me.G, Me.B, Me.A
End Function
Dim myFace As tFace
myFace.col.SetValue(200, 255, 127, 0)
'...
myFace.col.UseToDraw()
ErosOlmi
18-11-2015, 19:53
Proposed syntax by Petr is an advantage of those programming languages born since he beginning as Object Oriented.
Numbers are a primitive class that can be extended.
Strings are a primitive class that can be extended.
... and so on.
For programming languages born as procedural like thinBasic a syntax like 1.Hour.Ago is almost impossible unless we change the foundation of the core language.
There are some possibilities we can adopt, maybe slowing down a bit source interpretation.
I already have a hook in Core engine to scan for dotted notation almost for everything but then we need to adhere to some standards: how the language must behave?
What does it mean a number (1) followed by a term (Hour), followed by a term (Ago), followed by ... and so on ?
Is whatever meaning we can think always the same for the all similar situation?
Is 1.Divided.2 something in which the language can behave like when it encounters 1.Hour.Ago?
That's the problem I have to face when I thinBasic have to interpret a source code on the fly.
Petr Schreiber
18-11-2015, 23:05
The similar feature is "extension method" in C#. But I would not say it is necessarily OOP based, it is just syntactic sugar.
Here is proof of concept demo:
Uses "Console", "DT"
Long timeLimit = 1
'String code = "timeLimit.hours.ago" ' -- Works too
String code = "1.hours.ago"
PrintL "Now: " + DT_GetTime()
Number nValue = InterpretMe(code)
PrintL "Hour ago: " + DT_MillisecToTime(nValue)
WaitKey
Function InterpretMe( pieceOfCode As String ) As Number
String token = ConsumeToken(pieceOfCode)
String extension
Number valueNow = GetValue(token)
If IsExtendableNumeric(token) Then
While Len(Assign$(GetExtension(pieceOfCode), extension))
If Len(extension) Then
' -- Here some validation for signature, not present...
Call extension(valueNow) To valueNow
Else
Exit While
End If
Wend
End If
Return valueNow
End Function
Function ConsumeToken(ByRef pieceOfCode As String) As String
String token = IIf$(InStr(pieceOfCode, "."), Extract$(pieceOfCode, "."), pieceOfCode) ' -- This is really bad, but works for our case
pieceOfCode = Mid$(pieceOfCode, Len(token)+1)
Return token
End Function
Function IsExtendableNumeric(token As String)
Long isLiteral = token = "0" Or Val(token) <> 0
Long isVariable = VARIABLE_Exists(token) ' -- Here would be SMART test against list of numeric variables, this is too general
Return isLiteral Or isVariable
End Function
Function GetValue(token As String) As Number
If token = "0" Or Val(token) <> 0 Then
Return Val(token)
Else
Return Val(Expand$("$"+token))
End If
End Function
Function GetExtension(ByRef pieceOfCode As String) As String
If Not StartsWith(pieceOfCode, ".") Then
Return ""
Else
pieceOfCode = LTrim$(pieceOfCode, ".")
Return ConsumeToken(pieceOfCode)
End If
End Function
' --
Function Hours(ByVal x As Number) As Number
Return DT_TimeToMillisec(x+":00:00.000")
End Function
Function Minutes(ByVal x As Number) As Number
Return DT_TimeToMillisec("00:"+x+":00.000")
End Function
Function Seconds(ByVal x As Number) As Number
Return DT_TimeToMillisec("00:00:"+x+".000")
End Function
Function Ago(ByVal x As Number) As Number
Return DT_TimeToMillisec(DT_GetTime) - x
End Function
Petr