Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

2009/05/07

How to become a programmer, How to choose programming language


Introduction


On many message boards and forums I've seen many wannabe programmers.
"Guys, I want to become a programmer! Can you help me?". Sounds
familiar, isn't it? Those wannabes were asking same basic questions, over and over:

  • "Which programming language should I learn?"
  • "Which programming language is the best?".
  • "Can you recommend a good book about programming?"

Each of those guys (well, maybe there also were few girls) appeared, asked question, got some answers, disappeared and was never heard of again. I assume that some of them maybe were able to learn something, and maybe even became a really skillful professionals, but I believe most of those people have failed to become programmers. Because to my opinion they were doing it wrong from the beginning.

What you should never do if want to become a programmer



  • Never ask "Which programming language is the best?" on any message board.

    This is because there is no "the best" programming language, but many people will think otherwise. Typically, asking this question anywhere will provoke horrible flamewar where each person will attemp to prove that their language is "the best one". Of course, few first responses might be helpful for you, people even might provide some polite, useful, and unbiased info, but (in most situations) the thread will quickly turn into flamewar, or people will start demonstrating various language features using complex constructs (which will be completely uncomprehensible for a wannabe). Either way, there will be a very good chance that all discussion won't be helpful for a newbie.

  • Don't waste your time searching for "the best book" about your programming language.
    You will waste more time searching than you could spend programming. You will need a book, but it isn't really important to get best available book, especially if you are just a beginner. The practice and writing code is more important than books, at least in the beginning. So if you are in doubt (about which book to read), pick any book about your language, and use it for study.


What is really important


Book and choice of language are secondary things. Here is a list of requirements to become a programmer:

  • You should have a really good motivation or a goal. "I want to become a professional and get paid a lot of $$$" won't work - because you don't need to be programmer in order to earn cash. However "I want to make my own game" will be perfect.
  • Programming should be always interesting and fun for you. If it isn't interesting, if you aren't having fun when you write programs, then you won't be able to learn it quickly and efficiently. If your first programs look like a miracle/wonder for you, and you feel joy and happiness once it is finished, then you will have no trouble learning more difficult aspects. However, if you are bored to death each time you want to write something, you are not going to learn much. You will probably decide not to learn programming.
  • Do not try to pick "the best" language. Try to pick language which is "the best" just for you. If you are more comfortable with Python than with C++, then you probably will achieve more with Python.
  • When you are practicing, you should stick with stuff which is interesting for you. Making test program that inverts matrices is boring - pure math, not much to do. However, making "tetris" is not boring. Try to avoid boring examples from book. Keep books nearby and frequently use it as reference, but in order to learn more you should solve interseting, real-life problems.


Specialization: one important question you should answer before you start


You can't (easily) become universal programmer that can write in every language on every operating system. You should decide what you want to program, and pick your language accordingly.
Below is a short list of languages with short descriptions and explanations about how they are commonly used.


  • Assembler

    Not really a langauge. Assembler is simply a mnemonic representation of CPU instruction codes. So, (although there were some advanced assembler packages, like MASM), it is tightly tied to CPU, and will be mostly useful when programming low-level otpimized routines for that CPU. It won't be easy to use it for large projects.

  • C

    One of the popular languages, right now mostly used with OpenSource software, mostly on Unix/Linux/BSD and other unix-like system. It is very close to assembler (you still manipulate memory directly), but isn't tied to CPU type, so, unlike Assembler, C code is portable.

  • C++

    High-level language, with some of C features, and with higher-level features: objects, templates, etc. This language is really complex, and although you can learn syntax in few days, it might year or two to master it. C++ is used in most applications on many platforms, in many different tasks. It is portable.

  • Python

    High-level interpreted language. Platform-independant, isn't supposed to be compiled into machine code.

  • Java

    High level language which is meant to be completely platform-independant. Java program compiles into pseudo-code of non-existent processor. The code is run using interpreter, which is available for several platforms. So it is a hybrid of compiled and interpreted language.

  • C# and .NET

    Microsoft's attempts to make another java. Also compiles into pseudocode, but resulting application will be windows-only, because interpreter is developed only for windows (yes, I know about "Mono project", and I know it isn't frequently used).

  • Perl

    Interpreted language suitable for text processing, scripts, making tools, also for web.

  • PHP

    Interpreted language, used on the web servers.

  • JavaScript

    Used in web-pages, hardly for anything else.

  • Shell

    Unix shell script language. Used for making tools and scripts.



There are also several languages I never used much:

  • Haskell
  • Prolog
  • Common Lisp
  • OCaml

I"ve heard a lot of good things about those but I didn't need to use any of them. All of those languages are supposed to be powerful, but they are not "mainstream", and they aren't used frequently. Anyway, many people recommend at least to take a look at them.


Things you should keep in mind when you select language



  • Interpreted languages have better development speed, but worse performance, when compared to compiled languages. I.e. You might create Python program using less time, but C++ program are likely to have better performance. Notice that this a not always true, but in most cases. It is easy to make slow C++ program, especially if you don't know what you are doing. Keep in mind that although you don't need always need maximum performance or maximum development speed, in some situation they are important. For example, you wouldn't want to throw all power of C++ to make a simple text processing program - it will be faster to make it using shell script, python, perl, etc. On other hand, it won't be wise to make a raytracer in python - it is possible thing to do, of course, but for this application you will need a good performance, low-level memory access, etc. Notice, that in this situation you might consider assembler, but development time will be too high, and good C++ compiler might be able to produce better code than you.
  • You might not want to be tied to just one operating system, architecture or platform. If you want to be able to switch platforms later, then you should avoid Assembler(it is linked to just one CPU type), C# and all .NET languages (right now they are basically Windows-only), and you should be extra careful with C++ and compiled languages. Several companies provide language extensions which will be a lot of trouble if you ever decide to port your application to another platform (or simply if you decide to use another compiler). FIne example of that is microsoft's "safe" version of C string manipulation routines - "strcpy_s" and similar. They are not in C++ standard, so if you decide to port your application, you will have to write those routines yourself, or replace them with something else. Also, all compiled languages need libraries to interact with operating system, or create GUI windows, etc. This is because that standard for those compiled languages typically doesn't define libraries for all tasks. Because of this you should be careful about what libraries you use - they shouldn't be available only on one platform.
  • Some languages (typically interpreted or high-level: java, python, etc) try to help you and do some things for you - manage memory, for example (Python, Java, etc). Other languages assume that you are the "smart one" and you know what you are doing. They don't babysit you, and you are supposed to free memory yourself (C, C++ in some cases). Some people like automatic memory management, some don't like it. Typically, if you want to have all things under your control, you won't like automatic memory management. Keep that in mind when selecting language.
  • If you want to program for web, then you will probably have to use interpreted languages: Perl, Python, PHP, JavaScript. Compiled languages can be used to the some extent, but they won't help you much. This is because PHP and Javascript are easy to integrate into page, and you can't do same thing with C++ program.
  • IF you are using Linux/Unix-like system, then the first thing you might want to learn are shell scripts. This is because they are used very frequently. Also you might want to learn Perl or Python - because they are also very popular and frequently are being used for making simple unix/linux tools.


Conclusion


This is it. Think about all that and pick language. If you still don't know what to choose, pick anything and start studying it, but remember that you can always select another language later.

2009/03/25

How to use sprintf/wsprintf with std::string/std::wstring


Explanation


One of the few problems with std::string (and std::wstring) class in C++ is the lack of sprintf function that would return std::string as result. Or sprintf-styled constructor would be nice to have. Of course, there are many alternatives to sprintf - boost format library, sstream class and QString class in Qt 4, but so far plain old sprintf is most compact and easy when compared to them. sstream requires several statements(lines) to make a simple formatted string. Unless you like it too much, it is an overkill for making small formatted string. Boost format library will require boost or a part of it. And Qt 4 QString class will require entire Qt installation, acceptance of one of few available licenses, and it still won't be as compact as sprintf.

Solution



The first thing that comes to mind is to create temporary buffer, sprintf into buffer, and then assign buffer to std::string class. When your programs grows, you'll eventually get sick of many temporary buffers, besides it would still require few lines of code. Here is better way to do that:
Str.h:


#ifndef STR_H
#define STR_H
#include

typedef std::string Str;
typedef std::wstring WStr;

WStr swprintf(const wchar_t* format, ...);
WStr vswprintf(const wchar_t* format, va_list args);
WStr swprintf(const WStr& format, ...);
WStr vswprintf(const WStr& format, va_list args);

Str sprintf(const char* format, ...);
Str vsprintf(const char* format, va_list args);
Str sprintf(const Str& format, ...);
Str vsprintf(const Str& format, va_list args);

#endif




Str.cpp:

#include "Str.h"

WStr swprintf(const wchar_t* format, ...){
va_list args;
va_start(args, format);
WStr result = vswprintf(format, args);
va_end(args);
return result;
}

WStr vswprintf(const wchar_t* format, va_list args){
const int bufferSize = 16384;
wchar_t buffer[bufferSize];
vswprintf(buffer, bufferSize, format, args);
return WStr(buffer);
}

WStr swprintf(const WStr& format, ...){
va_list args;
va_start(args, format);
WStr result = vswprintf(format, args);
va_end(args);
return result;
}

WStr vswprintf(const WStr& format, va_list args){
return vswprintf(format.c_str(), args);
}

Str sprintf(const char* format, ...){
va_list args;
va_start(args, format);
Str result = vsprintf(format, args);
va_end(args);
return result;
}

Str vsprintf(const char* format, va_list args){
const int bufferSize = 16384;
char buffer[bufferSize];
vsnprintf(buffer, bufferSize, format, args);
return Str(buffer);
}

Str sprintf(const Str& format, ...){
va_list args;
va_start(args, format);
Str result = vsprintf(format, args);
va_end(args);
return result;
}

Str vsprintf(const Str& format, va_list args){
return vsprintf(format.c_str(), args);
}





This will allow to quickly create formatted string in one function call.

Problems:



This code works with gcc on Linux system, but it might require some tweaking on different compilers. For example, mingw version of vswprintf has different number of arguments (it doesn't have "buffer size" argument), so it will need to be replaced by another function. In general, wchar_t-based printf functions might cause problems when making cross-platform application. For example, swnprintf exists on MSVC compiler but is missing in gcc. On other hand, default version of vswprintf used in MinGW compiler doesn't have "buffer size" argument, so it is vulnerable to buffer overruns (linux version of function doesn't have this problem).
And yet another problem is that linux/windows versions of wprintf-related functions might handle %s and %S differently. As I remember, in mingw compiler %S in swprintf does the same thing as %s in linux version of printf and vise versa. Those problems can be partially fixed by using few hacks, but people making portable applications with swprintf should be aware of those problems.

Another problem is that there is hard-coded size limit for created strings (it can be changed, but it still doesn't look "nice" when used with C++ string classes. This problem can be bypassed for std::string classes (by using vsnprintf which returns how much characters could not be written in buffer, so you could allocate buffer dynamically, then sprintf into it, and then assign it to std::string), but not for std::wstring (vswnprintf is not available on gcc, doesn't look like standard).

Other solutions


To my opinion, the best (not the fastest) way to make custom sprintf for std::string classes is probably to write it from scratch (in C++ it might be easier) or derive from existing C implementation of sprintf (for example, you can take one out of freebsd source repository). The reason for that is that several printf implementations might have differences. The problem here is that it won't be easy, and you probably will need some time to write standard-compliant (or "format-compliant") version of swprintf/sprintf which will operate on std::string/std::wstring. Of course, you can also implement limited version of those functions.

Another way is to make your own formatting routines or use already mentioned ones: boost format library, QString or sstream. This way you won't get sprintf function, but few formatting routines to use instead.

2009/03/07

C++ utf8 to wstring conversion routine


Some time ago I was looking for C++ conversion routine that could convert utf8 string(stored in std::string) into std::wstring and vice versa. It is certainly possible to do that using setlocale and some C functions, but I wanted something done in "pure C++". I did some research, didn't find anything, and after all wrote conversion routine myself (using information on wikipedia).

Here is the code:



Str.h:
#ifndef STR_H
#define STR_H
#include
#include

typedef std::string Str;
typedef std::wstring WStr;

std::ostream& operator<<(std::ostream& f, const WStr& s); std::istream& operator>>(std::istream& f, WStr& s);
void utf8toWStr(WStr& dest, const Str& src);
void wstrToUtf8(Str& dest, const WStr& src);

#endif




Str.cpp:
/*
Copyright (c) 2009 SegFault aka "ErV" (altctrlbackspace.blogspot.com)

Redistribution and use of this source code, with or without modification, is
permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Str.h"
#ifdef UTF8TEST
#include
#endif

void utf8toWStr(WStr& dest, const Str& src){
dest.clear();
wchar_t w = 0;
int bytes = 0;
wchar_t err = L'�';
for (size_t i = 0; i < src.size(); i++){
unsigned char c = (unsigned char)src[i];
if (c <= 0x7f){//first byte
if (bytes){
dest.push_back(err);
bytes = 0;
}
dest.push_back((wchar_t)c);
}
else if (c <= 0xbf){//second/third/etc byte
if (bytes){
w = ((w << 6)|(c & 0x3f));
bytes--;
if (bytes == 0)
dest.push_back(w);
}
else
dest.push_back(err);
}
else if (c <= 0xdf){//2byte sequence start
bytes = 1;
w = c & 0x1f;
}
else if (c <= 0xef){//3byte sequence start
bytes = 2;
w = c & 0x0f;
}
else if (c <= 0xf7){//3byte sequence start
bytes = 3;
w = c & 0x07;
}
else{
dest.push_back(err);
bytes = 0;
}
}
if (bytes)
dest.push_back(err);
}

void wstrToUtf8(Str& dest, const WStr& src){
dest.clear();
for (size_t i = 0; i < src.size(); i++){
wchar_t w = src[i];
if (w <= 0x7f)
dest.push_back((char)w);
else if (w <= 0x7ff){
dest.push_back(0xc0 | ((w >> 6)& 0x1f));
dest.push_back(0x80| (w & 0x3f));
}
else if (w <= 0xffff){
dest.push_back(0xe0 | ((w >> 12)& 0x0f));
dest.push_back(0x80| ((w >> 6) & 0x3f));
dest.push_back(0x80| (w & 0x3f));
}
else if (w <= 0x10ffff){
dest.push_back(0xf0 | ((w >> 18)& 0x07));
dest.push_back(0x80| ((w >> 12) & 0x3f));
dest.push_back(0x80| ((w >> 6) & 0x3f));
dest.push_back(0x80| (w & 0x3f));
}
else
dest.push_back('?');
}
}

Str wstrToUtf8(const WStr& str){
Str result;
wstrToUtf8(result, str);
return result;
}

WStr utf8toWStr(const Str& str){
WStr result;
utf8toWStr(result, str);
return result;
}

std::ostream& operator<<(std::ostream& f, const WStr& s){
Str s1;
wstrToUtf8(s1, s);
f << s1;
return f;
}

std::istream& operator>>(std::istream& f, WStr& s){
Str s1;
f >> s1;
utf8toWStr(s, s1);
return f;
}

#ifdef UTF8TEST
bool utf8test(){
WStr w1;
//for (wchar_t c = 1; c <= 0x10ffff; c++){
for (wchar_t c = 0x100000; c <= 0x100002; c++){
w1 += c;
}
Str s = wstrToUtf8(w1);
WStr w2 = utf8toWStr(s);
bool result = true;
if (w1.length() != w2.length()){
printf("length differs\n");
//std::cout << "length differs" << std::endl;
result = false;
}

printf("w1: %S\ns: %s\nw2: %S\n", w1.c_str(), s.c_str(), w2.c_str());

for (size_t i = 0; i < w1.size(); i++)
if (w1[i] != w2[i]){
result = false;
printf("character at pos %x differs (expected %.8x got %.8x)\n", i, w1[i], w2[i]);
//std::cout << "character at pos " << i << " differs" << std::endl;
break;
}

if (!result){
printf("utf8 dump: \n");
for (size_t i = 0; i < s.size(); i++)
printf("%2x ", (unsigned char)s[i]);
}

return result;
}

int main(int argc, char** argv){
std::wstring ws(L"фыва");
std::string s("фыва");
std::cout << ws << s << std::endl;
std::cout << wstrToUtf8(utf8toWStr("фыва")) << std::endl;
if (utf8test())
std::cout << "utf8Test succesful" << std::endl;
else
std::cout << "utf8Test failed" << std::endl;
return 0;
}
#endif



Code was successfully tested on 32bit linux system (see "utf8test()" routine) and seems to work. Should work on 32bit windows platform as well, but keep in mind that wchar_t on msvc has size of 2 bytes, so on windows platform routine won't handle unicode characters in range 0xffff..0x10ffff).

If you need routine like this, feel free to use it, just don't claim you wrote it.
Code is available under modified BSD license.