Qbasicnews.com
May 11, 2021, 11:11:37 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: Back to Qbasicnews.com | QB Online Help | FAQ | Chat | All Basic Code | QB Knowledge Base
 
   Home   Help Search Login Register  
Pages: 1 [2] 3 4
  Print  
Author Topic: Here's another....file I/O difficulties.  (Read 17152 times)
stylin
Ancient QBer
****
Posts: 445


« Reply #15 on: January 10, 2006, 07:01:38 AM »

Quote from: "na_th_an"
For scoped variables, yes. But I can picture people declaring *any* stuff wherever and then losing track of variable types and stuff.

I fiscourage it.

The key here is initialization - and efficiency. You don't want to declare variables in a function that might exit before they're even used - it's a waste. Furthermore, whenever possible, it's preferred to intialize variables, rather than declaring them and assigning to them later - again, it's a waste. When FB supports classes, this will be even more of an issue: a class' constructor might be an expensive operation to execute. Why construct it to default values only to overwrite those values in an assignment later? It's a waste; it's inefficient code.

Spaghetti code is non-intelligible wild-goose hunts, and it mainly refers to erratic control flow - it has nothing to do with when or where variables are declared. In C, you're forced to declare variables at the start of a function. QB, FB, C++, Java, etc. give you the option - and it's an option you must take if you want to write efficient - and sometimes safe - code. Hell, by default, QB and FB don't even require you to declare variables before use - and it's directly supported by the language!

For beginners and novices alike in the above languages - yes, QB too - I fully encourage variable declaration at the point of initialization. For QBers, this means declaring a variables immediately before their first use. It's just silly not to, IMO.
Logged

stylin:
na_th_an
*/-\*
*****
Posts: 8244



WWW
« Reply #16 on: January 10, 2006, 07:47:42 AM »

Let me quote myself: "For scoped variables, yes" Wink

Note that FB is not a OO language. When it is, maybe it's good. But now, it can be puzzling. Imagine that you, by mistake, declare the same variable twice in two distant points in the same "visible zone". The compiler will complain on the second, and you'll have to examine your code line by line to find out where the first was.

Note that declaring a static variable and giving it a value is not a waste, no matter where it is declared/initialized. It is allocated on a static data "segment" (to call it somehow) at compile time, so that means that:

Code:
DIM a AS INTEGER

IF foo THEN
   INPUT a
   a = a + 7
END IF


Code:
IF foo THEN
   DIM a AS INTEGER
   INPUT a
   a = a + 7
END IF


Will take the same space and be as fast. A different thing is dynamic structures, but I'd rather declare them on top, then initialize them when needed. That way you, at a sight, have all the stuff controlled. No need to fetch every variable declaration accross thousands of lines of code.

A very different thing is the scoped usage of variables in OO languages, or even pseudo OO ones. For example, a loop index variable is really handy to be declared in the very loop, for example in Java:

Code:
for (int i = 0; i < 100; i ++)
{ ... }


In that case, you know that "i" will be int just inside the brackets. But in fB, if you do:

Code:
DIM i AS INTEGER
FOR i = 0 TO 99
   ...
NEXT i


After the loop, i keeps being defined as integer. Unless I am missing something Cheesy
Logged

SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
stylin
Ancient QBer
****
Posts: 445


« Reply #17 on: January 10, 2006, 08:37:25 AM »

Quote from: "na_th_an"
Imagine that you, by mistake, declare the same variable twice in two distant points in the same "visible zone". The compiler will complain on the second, and you'll have to examine your code line by line to find out where the first was.

This gets us into an entirely different - although important - discussion. I'll be brief.

First, if a function is big enough to where you lose track of variable declarations - that is, the size of the function is such that it is non-trivial to find a particular variable declaration - then the function is too large; refactor it into seperate, smaller functions. Good functions are no more than 15-25 lines, a reasonable size for a language like BASIC. If your functions are larger, then they are probably carrying too much responsibility, and would benefit from being split up. This not only solves the problem of having acres of code to sift through the same scope, but also documents your code better, providing clear and descriptive comments for the functionality of your code in the form of function calls.

Second, if you find yourself running into name collision within a function, that's a clear sign that a) you may not need to declare another variable, b) you may need to provide a better name for the variable or c) the function is too large and is carrying too much responsibility - refactor into seperate functions. I see all three of these symptoms of less than ideal code all the time in QB and FB. There's simply no reason for it. Any reasonably written function that's under 25 lines should never suffer from name collision. If you do, then the problem is likely a) or b). Refactor. Additionally, in a well written function, variable declarations should be easy to find since the function is short enough to be seen as a whole at a glance.

In short, I see name collision and "variable-hunting" non-issues with well written code. (and one of the ways well written code is made possible is by Designing-Before-Coding®. A programmer with a plan rarely runs into issues such as these. I don't remember the last time I had a name conflict, except with language keywords - and that's FB fault, not mine :-?)

Quote
A different thing is dynamic structures, but I'd rather declare them on top, then initialize them when needed. That way you, at a sight, have all the stuff controlled. No need to fetch every variable declaration accross thousands of lines of code.

Again, you shouldn't have to search through thousands of lines of code for a local variable of all things. Why would you, anyway?

Quote
... in fB, if you do:

Code:
DIM i AS INTEGER
FOR i = 0 TO 99
   ...
NEXT i


After the loop, i keeps being defined as integer. Unless I am missing something Cheesy

No, you're right. That is a problem, and I've already asked v1ctor over at freebasic.net for this:
Code:
for i as integer = 0 to 420
   ...
next

Hopefully that will make it into the next official release. I cross my fingers Smiley
Logged

stylin:
na_th_an
*/-\*
*****
Posts: 8244



WWW
« Reply #18 on: January 10, 2006, 09:46:26 AM »

Sometimes you have really long functions (even longer if you do profusely comment!), and you can't split them. Take for example a fast syntactic analyzer. The fastest way to create it is with a SELECT CASE structure and a different entry for each keyword.

Note that I am an optimization and speed freak. Sometimes the "best looking algorithm" and the "best split function" are also way slower than uglier counterparts. When I coded my last finished QB game (i.e. Jill) the movement subroutine took up to 400 lines or so. I could've split it in subroutines, but the amount of data needed to be passed back and forth would have turned the process into a snail walking over sand :lol: That's why my code style is not always very ... rational.

Besides, I'm working now doing lots of web-coding mostly in Java, JSP and PHP, and I can assure you that you will find 1,000 lines functions quite easily :lol: specially when you have html rendering plus database handling plus open directory reading plus connection to a mail server plus call to a PDF generating library all in place (I mean, just the calls to all those subsystems take lots of lines - I just wrote a SQL query that took 15 lines five minutes ago Cheesy).

I think I'm missing something. What I claim is for declaration on top of your function/sub or main section. I am not encouraging module globals.

You claim to declare variables when they are used. And you talk about scope. As far as I know (correct me if I'm wrong, I've been several months unaware of additions to fB), then only way you have to isolate visibility in BASIC is inside a FUNCTION or a SUB. In C++ or Java you have your brackets so you have a perfect way to isolate chunks of code - this makes your life easier. In this case, I find extremely useful declaring and instancing objects when they are needed, in the fashion of:

Code:
if (iConnectorStream != null)
{
   StatementGenerator myGenerator = new StatementGenerator (blah, 1);
   ...
   // Here you can use myGenerator
}

// Here myGenerator is not declared


But in BASIC this is not possible (again, AFAIK Wink). Until it is, I'll keep declaring my stuff on top of each SUB/FUNCTION.

I suppose it's a matter of taste, but I find it more comfortable having all my declarations packed in a special section in the code rather than scattered around thousands of lines Cheesy plus I don't see the advantages of what you are suggesting, mainly 'cause you can't isolate chunks of code.
Logged

SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
red_Marvin
Na_th_an
*****
Posts: 1509



WWW
« Reply #19 on: January 10, 2006, 10:54:02 AM »

Maybe it would be good to have this in fB:
Code:
SCOPE
  DIM foo as integer
  '...
  ' foo available
END SCOPE
' foo not available


EDIT: According to stylins's post it is being implemented...
Logged

/post]
stylin
Ancient QBer
****
Posts: 445


« Reply #20 on: January 10, 2006, 11:05:30 AM »

Quote from: "na_th_an"
Sometimes you have really long functions (even longer if you do profusely comment!), and you can't split them. Take for example a fast syntactic analyzer. The fastest way to create it is with a SELECT CASE structure and a different entry for each keyword.

Yes, design should adapt the needs at hand, obviously. I'm not suggesting a blanket coding style, however in my experience, the companies I've worked for have required similar styles - in C++, variable initialization is a given. Granted, you have some leeway with function length since the IDE you're using can help you out (outlining/folding, function selection, statement completion, declaration/definition locating, etc.) FreeBASIC does not currently have such an exclusive IDE, but I'm of the mind that an IDE shouldn't be the main factor in how you implement code, either.

Quote
Note that I am an optimization and speed freak. Sometimes the "best looking algorithm" and the "best split function" are also way slower than uglier counterparts. When I coded my last finished QB game (i.e. Jill) the movement subroutine took up to 400 lines or so. I could've split it in subroutines, but the amount of data needed to be passed back and forth would have turned the process into a snail walking over sand :lol: That's why my code style is not always very ... rational.

Again, it depends on who's reading your code. For hobby work, either individually or with a small team, then feel free to code however it takes to be better productive, of course. For employers, software teams mandate a certain style, regardless of your personal preference. I realize that FreeBASIC, C, C++, Java, etc. are different languages. However, I strongly feel that beginning programmers should learn habits similar to that of those languages, since 1) it will only help them in transitioning over, and 2) languages like FreeBASIC are designed to give you the freedom to be able to do that (make the transition from FB to, for example C++, very easy by following similar programming paradigms).

Quote
Besides, I'm working now doing lots of web-coding mostly in Java, JSP and PHP, and I can assure you that you will find 1,000 lines functions quite easily :lol: specially when you have html rendering plus database handling plus open directory reading plus connection to a mail server plus call to a PDF generating library all in place (I mean, just the calls to all those subsystems take lots of lines - I just wrote a SQL query that took 15 lines five minutes ago Cheesy).

I'm not very familiar with web-programming, but no Java function I've ever been assigned to has been 1000 lines long ... I'd probably shoot myself.

Quote
I think I'm missing something. What I claim is for declaration on top of your function/sub or main section. I am not encouraging module globals.

I know you're not. We're on the same page.

Quote
In C++ or Java ... code snipped ... But in BASIC this is not possible (again, AFAIK Wink). Until it is, I'll keep declaring my stuff on top of each SUB/FUNCTION.

Wink prepare to change, my friend:
Code:
'' note: op_new_???(...) and op_delete(...) are functions from my MACRO library ...

if not( iConnectorStream = null ) then
 scope
    dim as StatementGenerator ptr myGenerator = op_new_StatementGenerator( blah, 1 )
    ...
    '' Here you can use myGenerator
    ...
    op_delete( myGenerator )
 end scope
end if

'' Here myGenerator is not declared


http://www.freebasic.net/wiki/wikka.php?wakka=KeyPgScope
Logged

stylin:
na_th_an
*/-\*
*****
Posts: 8244



WWW
« Reply #21 on: January 10, 2006, 11:52:44 AM »

Nice to know new stuff :lol:

In that scenario, I concur and agree with you.

Anyway, for every variable which won't be used within a scope, I'd  declare it on top rather than doing it just before it's used. Call it "cosmetic". I just find it more handy, and useful. 'Cause there's an advantage on declaring stuff when it's used if you are inside a delimited chunk of code (that scope thing), but there isn't if you are not.

Btw, when giving hints to code in BASIC, I always encourage coding in the right way, and the right way (for me) is the "pseudo OO" way, I mean, trying to use (or at least emulating) encapsulation as much as possible.

And, trust me, I'm usually working adapting already coded software to fit our needs at work. That means that I've played around with the guts of postnuke, squirrelmail, docmanager and other systems. And I can assure you that 1,000 lines functions are quite common :lol: (and a nightmare). And in Java it's even worse. Sometimes splitting your methods so much is a bad move, mainly 'cause of massive exception handling. Of course you have to break your code in as many functional parts as possible, that's the key to structured programming, but I just want to tell you that "Good functions are no more than 15-25 lines" is not always appliable.
Logged

SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
Zack
*/-\*
*****
Posts: 3974



WWW
« Reply #22 on: January 10, 2006, 01:20:20 PM »

Back on the subject of Ethan Winer's clever little encryption there...
Well here it is in my expanded form. Shown is code for both ciphering and deciphering. It's a few lines longer, but a heckuva lot clearer.
Code:
OPTION EXPLICIT
CONST Text="Move 32nd platoon SSW 10 miles"
CONST Password="armypassword"

DIM AS STRING DecipheredText,CipheredText
DIM TempChar AS BYTE,PswdPos AS INTEGER,I AS INTEGER

PswdPos=1
FOR I=1 TO LEN(Text)
    IF PswdPos > LEN(Password) THEN PswdPos=1
    TempChar=ASC(MID$(Text,I,1)) XOR ASC(MID$(Password,PswdPos,1))
    CipheredText=CipheredText + CHR$(TempChar)
    PswdPos=PswdPos + 1
NEXT

PRINT "Text: ";Text
PRINT "Password: ";Password
PRINT "Ciphered text: ";CipheredText

PswdPos=1
FOR I=1 TO LEN(CipheredText)
    IF PswdPos > LEN(Password) THEN PswdPos=1
    TempChar=ASC(MID$(CipheredText,I,1)) XOR ASC(MID$(Password,PswdPos,1))
    DecipheredText=DecipheredText + CHR$(TempChar)
    PswdPos=PswdPos + 1
NEXT

PRINT "Deciphered text: ";DecipheredText
SLEEP

PswdPos indicates which character in the password string is to be used for each iteration. It's incremented each time, and reset once it exceeds the length of the password.
Logged

f only life let you press CTRL-Z.
--------------------------------------
Freebasic is like QB, except it doesn't suck.
stylin
Ancient QBer
****
Posts: 445


« Reply #23 on: January 10, 2006, 02:12:25 PM »

Nice work! That looks alot better. While we're on the subject of functions, though, this may be a good time to show their usefulness. Additionally, you can use the string-indexing operator ( [] ) to crisp up that code even more:
Code:
option explicit
option byval

function CipherText( text as string, key as string ) as string
    dim as integer textIndex = 0, keyIndex = 0
    dim as string result = string( len( text ), 0 )

    while( textIndex < len(text) )
        if( keyIndex > len(key) ) then keyIndex = 0
        result[textIndex] = text[textIndex] xor key[keyIndex]
        textIndex += 1 : keyIndex += 1
    wend
    return result
end function

const originalText as string = "Move 32nd platoon SSW 10 miles"
const password as string = "armypassword"

dim as string cipheredText : cipheredText = CipherText( originalText,password )
print "  original Text: " ; originalText
print "       Password: " ; Password
print "  Ciphered text: " ; cipheredText

dim as string decipheredText : decipheredText = CipherText( cipheredText,password )
print "Deciphered text: " ; decipheredText

sleep : end 0

Here, we solely work with the byte values of the strings, which is what operator[] gives us. As you may be able to guess, this is much more efficient than converting back and forth from strings to integers again and again.
Logged

stylin:
Zack
*/-\*
*****
Posts: 3974



WWW
« Reply #24 on: January 10, 2006, 02:15:31 PM »

I didn't know about that! Kinda renders MID$ less useful than it was in QB.
Now I'm working on another encryption method. I may post it, but I might offer it up to be cracked first as a challenge.
Logged

f only life let you press CTRL-Z.
--------------------------------------
Freebasic is like QB, except it doesn't suck.
stylin
Ancient QBer
****
Posts: 445


« Reply #25 on: January 10, 2006, 02:22:38 PM »

Quote from: "Zack"
I didn't know about [the string indexing operator]! Kinda renders MID$ less useful than it was in QB.

Just a little. It would still be very inefficient to try and return large substrings using [] alone.

Quote
Now I'm working on another encryption method. I may post it, but I might offer it up to be cracked first as a challenge.

You're just an encrypting fool, aren't ya? Wink
Logged

stylin:
Moneo
Na_th_an
*****
Posts: 1971


« Reply #26 on: January 10, 2006, 10:36:46 PM »

Zack and Stylin,

The new encryption logic that you guys derived from Winer's algorithm is "crisper" and prettier, but, it doesn't work the same. I ran your new code against Winer's code in the same program. For the same original text and password, the ciphered text is the same for the first 11 characters, and then is different.

If the new version does not yield the same results, then it cannot qualify as being the same algorithm.

Run a test yourselves.
*****
Logged
stylin
Ancient QBer
****
Posts: 445


« Reply #27 on: January 11, 2006, 03:27:44 AM »

The problem was due to string copying; the string was getting truncated at the null character when it was being passed in. The original code you posted earlier used the same string. Passing by reference and explicitly copying solves the problem. Here is the updated code:
Code:
option explicit
option byval

function ZackText( byref text as string, key as string ) as string
    dim as string result => text
    dim as integer textIndex = 0, keyIndex = 0

    while( textIndex < len(text) )
        if( keyIndex = len(key) ) then keyIndex = 0
        result[textIndex] xor= key[keyIndex]
        textIndex += 1 : keyIndex += 1
    wend
    return result
end function

function WinerText( byref text as string, key as string ) as string
    dim as string result => text
    dim as integer L = len(key)
    dim as integer i, Pass

    for i = 1 to len(text)
         Pass = asc(mid$(key, (i mod L) - L  * ((i mod L) = 0), 1))
         mid$(result,i,1) = chr$(asc(mid$(text,i,1)) xor Pass)
    next
    return result
end function

const originalText as string = "Move 32nd platoon SSW 10 miles"
const key as string = "armypassword"

dim as string zackedText : zackedText = ZackText( originalText, key )
dim as string wineredText : wineredText = WinerText( originalText, key )
dim as string deZackedText : deZackedText = ZackText( zackedText, key )
dim as string deWineredText : deWineredText = WinerText( wineredText, key )

print "  original Text: " ; originalText
print "       Password: " ; key
print
print "    Zacked text: " ; zackedText
print "   Winered text: " ; wineredText
print
print "  DeZacked text: " ; deZackedText
print " DeWinered text: " ; deWineredText

sleep : end 0
Logged

stylin:
Zack
*/-\*
*****
Posts: 3974



WWW
« Reply #28 on: January 11, 2006, 10:33:26 AM »

Well I haven't learned references, pointers, etc. yet. I'll examine that code and see what it means.
Thanks for pointing that out, Moneo - usually when I test encryption stuff I test to see if it deciphers correctly - and not to see whether it comes out the same as another method of ciphering.
Logged

f only life let you press CTRL-Z.
--------------------------------------
Freebasic is like QB, except it doesn't suck.
stylin
Ancient QBer
****
Posts: 445


« Reply #29 on: January 11, 2006, 10:54:09 AM »

Quote from: "Zack"
Well I haven't learned references, pointers, etc. yet. I'll examine that code and see what it means.

Passing a variable by value to a function means that a copy of the variable is made, and that copy is what the function refers to.

Passing a variable by reference means that the object a function recieves is a reference to the original variable. Many compilers implement references as pointers internally, but that should not be relied upon. A reference should be considered as the original variable. Any changes made to a reference affect the original variable. Passing by reference is the default behavior in both QB and FB.

Now, since many compilers implement references as pointers, passing a variable by reference often leads to faster code when passing UDTs and strings because - on my system - a pointer is 4 bytes. UDTs and strings can be potentially quite large and expensive objects to copy. Passing them by reference ensures that these copies are not made, and only a 4-byte pointer is passed instead. You need to be careful when passing by reference - especially since FB doesn't have true constant variables - because again, any changes you make to the reference are made to original variable as well. So, when passing variables that you don't want to be changed (accidentally or otherwise) pass by value, unless the object is a large UDT or string.

In the above code, "option byval" sets the default passing convention to by value. In both functions, "key" is being passed by value, since I don't want to accidentally change it. "text" is being passed by reference because for some reason FB truncates a string being passed to a function if it contains a null (chr$(0)) character but, curiously, this truncation does not happen if the string is copied in code. So, "text" is passed by reference to in order to avoid it being copied internally.
Logged

stylin:
Pages: 1 [2] 3 4
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!