It's been a while since I found out something peculiar about Caché's language, Caché Object Script. It is not really a bug, since it's registered at the documentation, but I don't think it's very natural or straightforward.
If you remember your mathematic class when you were a child, you might give the correct answer for this expression: 1 + 2 * 3 (* means multiplication, if you don't already know =P). If your answer is 9, you probably skip some classes, since the correct answer is 7. That's because in math, multiplication operator has precedence over addition and subtraction operators (see this link). It means that if you don't put parentheses (which is the "right way" to express the order of operations, if you want), you must do multiplication before addition.
Well, most of programming languages I know, consider mathematics (what is absolutely normal, since science computer was born from maths, together with eletric engineerings).
Examples:
Oracle database, I can do: SELECT 1 + 2 * 3 FROM DUAL
, and the answer will be 7. So Java, C/C++, Delphi/Pascal, gives us the correct answer, 7.
But with Caché Object Script, the answer is 9. Try open a terminal, and execute the following: WRITE 1 + 2 * 3
, the answer will be 9.
This happens because this language doesn't follow mathematics pattern, neither most of language's. Fine, in fact, it's a matter of implementation, and it's in documentation, but I can't stop looking it badly. Even worse when I am used to the rest of world's convention, used to "right" operators precedence. Oh well, the language can choose if it will follow or not, any convention. But if you do not, especially math's conventions, you might cause some errors.
I just payed attention to this, because one loop of mine wasn't working. Being familiar with other programming languagens, I didn't think a simple expression could be wrong (the max boundary of my loop was the result of a expression like I showed). After check the rest of algorith twice, I was just blessed by a hunch, and after some tests and debugging, I realized that I should have put some parentheses in the expression. After doing that, I checked the documentation and it was really there: operators precedence is strictly left to right, when no parentheses are found.
So, I just start wondering why those language designers made it, why they made this choice? Did they want to be 'cool', not just like everyone else, or maybe were they rebels with or without a cause?
I believe it was not the case. I think it was just because the implementation of script's execution, which is easier to do when you don't consider math operators precedence. Laziness. Less effort law, the law that really moves this world, despite Newton's gravity =P.
Even being a script language is not really an excuse. Javascript is also an script. But it goes with the rest of the world. Just try document.write(1 + 2 * 3)
and you'll get a nice 7.
u_u
quinta-feira, 26 de julho de 2007
Caché Operators
Postado por
Andarilho
às
11:07
0
comentários
Marcadores: caché, operator precedence, programming, wtf
The forgotten parameter
While searching the source code of %IO.ServerSocket to write the previous posts (about sockets and ServerSockets and jobs), I just found out something at least, curious.
The method ListenJob
from %IO.ServerSocket has as 6th parameter, pForeground
, a boolean value which default is zero (means false in Caché). The (poor and little) documentation of this method even cites this parameter. The name of the parameter might indicate us the idea of controlling if spawned jobs would run in background or not, or even if the own method would run in background or not.
After some tests, I realized that the behaviour of ListenJob
method didn´t change, even if I changed this parameter. So I went to see and analyse the source code, and surprise: this parameter IS USED NOWHERE. Oh yes, it´s declared in method's formal description, and nowhere else.
Dumb, very dumb, I thought. But, I decided to give it a chance, and check some possibilities that might have led to this situation.
First theory: this class might be used in older versions of Caché, and to keep compatibility, they just left the method as it was. Theory status: not valid. In this docs of version 5.0, this class EVEN EXISTS.
Second theory: in some newer version, it might be used for something. Theory status: highly not probable. I don't have version 2007.1 here, so I can't see the sources, but as shown on this version's doc, I don't see any diferences at this class.
Last theory: someone just forgot the parameter there, left it alone and useless. Theory status: it's the theory I accept as true, for now.
Just to mention, I use Caché's version 5.2, therefore all links I post to documentation is for this version. So, in previous posts, all links go to 5.2, although in this case, all classes seemed the same, as I looked at 2007.1 docs.
There are things in this world... ¬¬
Postado por
Andarilho
às
06:08
0
comentários
Marcadores: caché, network, problems, programming, wtf
terça-feira, 24 de julho de 2007
More sockets in Caché
Returning to the subject of last post, about Caché's sockets, lets explore other possibilities.
At last post, I showed a simple example of how to create sockets, both server and client sockets. However, that example had a limitation: at the ServerSocket, the code shown only accepted one request, and after dealing with the connection, it ended its execution. As an example, it is still valid, but in a real-scenario, it's too limited.
In fact, the class %IO.ServerSocket has another method, which allows us to create a Server socket more alike a Java's ServerSocket. This method is ListenJob
.
First, lets see a simple example code:
Class teste.ServerSpawnSocket Extends %RegisteredObject
{
ClassMethod server()
{
set sock = ##class(%IO.ServerSocket).%New()
set st = $$$OK
w "Starting server...", !
// open serverSocket, param:
// port, timeOut, status
w sock.Open(7777, -1, st), !
w st, !
// server to listen incoming connections,
// and when it arrives, spawns a new job in background
// params:
//
// timeOut,
// classNameContainingMethodToBeCalled,
// jobArguments,
// socketClassName (default: %IO.ServerSocket),
// maxNumberOfJobs (default: -1),
// runInForeground (default: 0 - no),
// status
w sock.ListenJob(-1, "teste.ServerSpawnSocket", "", , , , st), !
w st, !
w "Closing server...", !
quit
}
//===================================================
ClassMethod OnConnected(StreamHandler As %IO.DeviceStream, AnotherArgs)
{
set st = $$$OK
// reading from socket, param:
// maxStringSize, timeout, status, lineTerminator
set ^someVar("read from tcp") = StreamHandler.ReadLine(50, 30, st, $c(13))
// writing to socket, param:
// stringToBeWritten, automaticFlush, status
d StreamHandler.Write("Goodbye Dolly", 1, st)
d StreamHandler.Close(st)
set ^someVar("status") = st
quit
}
}
The method server()
is quite simple, having more lines of comments than lines of code =P. After we create an object, again we call method Open
. In this method, we define the port that the socket will keep listening. But the method we are more interested now, is the following one, ListenJob
This method does the following: when a new request arrives at the socket, if there's no restriction to request's address, the method creates a new job in background, passing as parameter an object of class %IO.DeviceStream, which holds the data stream created for the connection. But a question arises: what method does Caché calls? Well, after surfing through source-code of %IO.ServerSocket, I found out that after calling some internal methods of its own class, the object invokes a classmethod (in Java, we call it static class method) OnConnected
, of the class whose name was passed as the second parameter of ListenJob
.ListenJob
also can control the max number of concurrent jobs, which is defined in 5th parameter. The first parameter is our old known friend timeout, that in our example, is set to -1, to never expire. The third parameter might be made of a list, with parameters to be passed to OnConnected
method. The 6th parameter is useless (I'll talk about it in the future), and the last parameter is also an old friend, an object with the status of method's execution.
At the example, we can see that we passed as parameter, the name of it's own class, but it could have been another class as well. The important is that the class has the class method OnConnected
. The method's interface can be seen at the example. (IMPORTANT: this interface is not fixed or official, since I didn't find any reference to this in documentation, just in sources).
Inside OnConnected
method, we can manipulate the data stream as we wish, the example just read and write something from/to the stream, before closing the connection.
That's it. Hope it is usefull.
Postado por
Andarilho
às
06:49
0
comentários
Marcadores: caché, network, programming, sockets
segunda-feira, 23 de julho de 2007
Sockets and Caché
Some days ago, at Caché´s google groups, someone asked how to use sockets in Caché. I also have never used sockets directly in Caché, I thought it would be nice to find out how to. As I frequently say, Caché documentation is far from good docs, as Sun´s javadocs, therefore, a lot of things I discovered was through "feeling" and suppose-test-check cycles, although in this specific case, it was a bit easy.
Below, the example code I have posted in google groups. You can put this methods in any class, so you can test yourself:
ClassMethod connect()
{
set sock = ##class(%IO.Socket).%New()
set st = $$$OK
w "Starting", !
// connecting, param:
// address, port, timeout, status
w sock.Open("127.0.0.1","7777",-1, st), !
w st, !
// reading from socket, param:
// maxStringSize, timeout, status, lineTerminator
w sock.ReadLine(50, 30, st, $c(13)), !
// writing to socket, param:
// stringToBeWritten, automaticFlush, status
d sock.Write("We are the champions", 1, st)
quit
}
//===================================================
ClassMethod server()
{
set sock = ##class(%IO.ServerSocket).%New()
set st = $$$OK
w "Starting server...", !
// open serverSocket, param:
// port, timeOut, status
w sock.Open(7777, -1, st), !
w st, !
// server to listen incoming connections, param:
// timeOut, status
w sock.Listen(-1, st), !
w st, !
// writing to socket, param:
// stringToBeWritten, automaticFlush, status
d sock.Write("I am the champion", 1, st)
// reading from socket, param:
// maxStringSize, timeout, status, lineTerminator
w sock.ReadLine(50, 30, st, $c(13)), !
w sock.Close(), !
w "Closing server...", !
}
The first method, connect()
, uses a %IO.Socket, which implements a basic client socket. If you are familiar to Java, you'll realize this class is very simple to use. Actually, after you create the object, you can just cal method Open
, with the host´s address and port, a timeout (-1 at the example means no timeout at all) and a status object as parameters.
After connected, you can use methods from %IO.DeviceStream (which %IO.Socket inherits), to read/write data stream.
//===================================================
The second method show above, server()
, uses a %IO.ServerSocket. The difference is that ServerSocket implements a server, i.e., a socket that keeps listening requests, and IO.Socket connects to a ServerSocket. Unlike Java´s ServerSocket, which returns a Socket object, %IO.ServerSocket can be used as an ordinary socket. We can see that the same methods are used to write/read to/from both socket objects.
It is also possible to keep the ServerSocket listening, and when a connection is attempted, start other job in background, to handle the new connection. I will explore this in some future post.
Postado por
Andarilho
às
12:49
0
comentários
Marcadores: caché, network, programming, sockets
WTF is it about?
I am a person who doesn´t really like blogging. Unfortunatelly, some subjects I talk about at my other blog, in portuguese, could really interest a broader audience, since it seems there is a lack of research material on Caché.
So, I´ll be replicating here some of my posts. That´s it.
Postado por
Andarilho
às
12:00
0
comentários