Fun to Program – Hello World!

Date: 2013/08/02 (initial publish), 2021/08/02 (last update)

Previous Post Top Next Post

TOC

This was originally written and created around 2013 and may require to be updated. (2021)

“Hello World!”

Here are example code snippets to print “Hello World!” and somethings we should be aware of for each language.

Shell

The most basic programing language: Shell.

Source code for the hello shell script

#!/bin/sh
# my first shell program
echo "Hello, world!"

Execution of the hello shell script

$ chmod 755 hello
$ ls -l ./hello
-rwxr-xr-x 1 osamu osamu 56 Mar 11 21:52 ./hello
$ file ./hello
./hello: POSIX shell script, ASCII text executable
$ ./hello
Hello, world!

TIP: Here, the interactive shell to be Bash and the non-interactive shell to be Dash unless explicitly mentioned. They are POSIX shell.

Python

Source code for the hello Python script (simple)

#!/usr/bin/env python3
# My first Python program (bare bones)
print("Hello, world!")

Python programs are usually written as follows:

Source code for the hello Python script (with __name__)

#!/usr/bin/env python3
# My first Python program (nicer style)
def main():
    print("Hello, world!")

if __name__ == '__main__': 
    main() 

If you use wish to ensure to use the Python interpreter offered by the Debian system, the starting line should use as follows.

Source code for the hello Python script (force the Python interpreter offered by the Debian system)

#!/usr/bin/python3
def main():
    print("Hello, world!")

if __name__ == '__main__': 
    main() 

Execution of the hello Python script

$ chmod 755 hello
$ ls -l ./hello
-rwxr-xr-x 1 osamu osamu 99 Mar 11 21:52 ./hello
$ file ./hello
./hello: Python script, ASCII text executable
$ ./hello
Hello, world!

Lua

Source code for the hello Lua script

#!/usr/bin/lua
-- my first lua program --
print("Hello, world!")

Execution of the hello Lua script

$ chmod 755 hello
$ ls -l ./hello
-rwxr-xr-x 1 osamu osamu 65 Mar 11 21:52 ./hello
$ file ./hello
./hello: Lua script, ASCII text executable
$ ./hello
Hello, world!

Perl

Source code for the hello Perl script

#!/usr/bin/perl
# my first python program
print("Hello, world!\n");

Execution of the hello Perl script

$ chmod 755 hello
$ ls -l ./hello
-rwxr-xr-x 1 osamu osamu 68 Mar 11 21:52 ./hello
$ file ./hello
./hello: Perl script, ASCII text executable
$ ./hello
Hello, world!

C

Source code in C language

#include <stdio.h>
#include <stdlib.h>
/* my first C program */
int main()
{
    printf("Hello, world!\n");
    return EXIT_SUCCESS;
}

Here, I need to include header files:

Let’s compile hello.c to create the ELF object hello and run it.

$ gcc -Wall -o hello hello.c
$ ls -l ./hello
-rwxrwxr-x 1 osamu osamu 6687 Aug 17 23:41 ./hello
$ file ./hello
./hello: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linke
d (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0e6a4d2048e4d49278a909
8394272f2138f9cf14, not stripped
$ ./hello
Hello, world!

Let’s list linked libraries to the ELF object hello.

$ ldd hello
    linux-vdso.so.1 (0x00007fffb233b000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00002aaaaaccf000)
    /lib64/ld-linux-x86-64.so.2 (0x00002aaaaaaab000)

Here, notable libraries are:

Let’s list symbols defined in the ELF object hello.

$ nm -n hello
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
                 U __libc_start_main@@GLIBC_2.2.5
                 U puts@@GLIBC_2.2.5
00000000004003a8 T _init
0000000000400410 T _start
0000000000400440 t deregister_tm_clones
0000000000400470 t register_tm_clones
00000000004004b0 t __do_global_dtors_aux
00000000004004d0 t frame_dummy
00000000004004fd T main
0000000000400520 T __libc_csu_init
00000000004005b0 T __libc_csu_fini
00000000004005b4 T _fini
00000000004005c0 R _IO_stdin_used
00000000004006d8 r __FRAME_END__
00000000006006e0 t __frame_dummy_init_array_entry
00000000006006e0 t __init_array_start
00000000006006e8 t __do_global_dtors_aux_fini_array_entry
00000000006006e8 t __init_array_end
00000000006006f0 d __JCR_END__
00000000006006f0 d __JCR_LIST__
00000000006006f8 d _DYNAMIC
00000000006008d0 d _GLOBAL_OFFSET_TABLE_
0000000000600900 D __data_start
0000000000600900 W data_start
0000000000600908 D __dso_handle
0000000000600910 B __bss_start
0000000000600910 b completed.6392
0000000000600910 D _edata
0000000000600910 D __TMC_END__
0000000000600918 B _end

Here, symbol types are:

Let’s look into how hello.c is compiled by stopping before the assembler by creating assembler code as hello.s with the -S option.

$ gcc -S hello.c
$ cat hello.s
    .file    "hello.c"
    .section    .rodata
.LC0:
    .string    "Hello, world!"
    .text
    .globl    main
    .type    main, @function
main:
.LFB2:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $.LC0, %edi
    call    puts
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE2:
    .size    main, .-main
    .ident    "GCC: (Debian 4.8.1-9) 4.8.1"
    .section    .note.GNU-stack,"",@progbits

Please note this is written in the AT&T assembler style. We will get back to its details later.

TIP: Several lines with .cfi_... in the assembler code are the DWARF CFI directives which help debugger to do backtrace on the modern ABI system without frame pointers (FP). See CFI support for GNU assembler (GAS).

C++

Source code in C++ language

#include <iostream>
#include <stdlib.h>
//  my first C++ program
int main ()
{
    using namespace std;
    cout << "Hello World!" << endl;
    return EXIT_SUCCESS;
}

Let’s compile hello.cxx to create the ELF object hello and run it.

$ g++ -Wall -o hello hello.cxx
$ ls -l ./hello
-rwxrwxr-x 1 osamu osamu 8368 Aug 17 23:41 ./hello
$ file ./hello
./hello: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked...
$ ./hello
Hello World!

Let’s list linked libraries to the ELF object hello.

$ ldd hello
    linux-vdso.so.1 (0x00007ffff85fe000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00002aaaaaccf00...
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00002aaaaafd2000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00002aaaab2d0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00002aaaab4e6000)
    /lib64/ld-linux-x86-64.so.2 (0x00002aaaaaaab000)

Let’s list symbols defined in the ELF object hello.

$ nm -n hello
                 U __cxa_atexit@@GLIBC_2.2.5
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
                 U __libc_start_main@@GLIBC_2.2.5
                 U _ZNSolsEPFRSoS_E@@GLIBCXX_3.4
                 U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
                 U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
                 U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GL...
                 U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBC...
0000000000400698 T _init
0000000000400750 T _start
0000000000400780 t deregister_tm_clones
00000000004007b0 t register_tm_clones
00000000004007f0 t __do_global_dtors_aux
0000000000400810 t frame_dummy
000000000040083d T main
0000000000400864 t _Z41__static_initialization_and_destruction_0ii
00000000004008a1 t _GLOBAL__sub_I_main
00000000004008c0 T __libc_csu_init
0000000000400950 T __libc_csu_fini
0000000000400954 T _fini
0000000000400960 R _IO_stdin_used
0000000000400ac8 r __FRAME_END__
0000000000600ad0 t __frame_dummy_init_array_entry
0000000000600ad0 t __init_array_start
0000000000600ae0 t __do_global_dtors_aux_fini_array_entry
0000000000600ae0 t __init_array_end
0000000000600ae8 d __JCR_END__
0000000000600ae8 d __JCR_LIST__
0000000000600af0 d _DYNAMIC
0000000000600cf8 d _GLOBAL_OFFSET_TABLE_
0000000000600d50 D __data_start
0000000000600d50 W data_start
0000000000600d58 D __dso_handle
0000000000600d60 B __bss_start
0000000000600d60 D _edata
0000000000600d60 D __TMC_END__
0000000000600d60 B _ZSt4cout@@GLIBCXX_3.4
0000000000600e70 b completed.6392
0000000000600e71 b _ZStL8__ioinit
0000000000600e78 B _end

There are many symbols starting with _Z. These are mangled symbols. We need to demangle these symbol with c++filt to make this readable.

$ nm -n hello|c++filt|fold
                 U __cxa_atexit@@GLIBC_2.2.5
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
                 U __libc_start_main@@GLIBC_2.2.5
                 U std::basic_ostream<char, std::char_traits<char> >::operator<<
(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char,
 std::char_traits<char> >&))@@GLIBCXX_3.4
                 U std::ios_base::Init::Init()@@GLIBCXX_3.4
                 U std::ios_base::Init::~Init()@@GLIBCXX_3.4
                 U std::basic_ostream<char, std::char_traits<char> >& std::endl<
char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >
&)@@GLIBCXX_3.4
                 U std::basic_ostream<char, std::char_traits<char> >& std::opera
tor<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char>
>&, char const*)@@GLIBCXX_3.4
0000000000400698 T _init
0000000000400750 T _start
0000000000400780 t deregister_tm_clones
00000000004007b0 t register_tm_clones
00000000004007f0 t __do_global_dtors_aux
0000000000400810 t frame_dummy
000000000040083d T main
0000000000400864 t __static_initialization_and_destruction_0(int, int)
00000000004008a1 t _GLOBAL__sub_I_main
00000000004008c0 T __libc_csu_init
0000000000400950 T __libc_csu_fini
0000000000400954 T _fini
0000000000400960 R _IO_stdin_used
0000000000400ac8 r __FRAME_END__
0000000000600ad0 t __frame_dummy_init_array_entry
0000000000600ad0 t __init_array_start
0000000000600ae0 t __do_global_dtors_aux_fini_array_entry
0000000000600ae0 t __init_array_end
0000000000600ae8 d __JCR_END__
0000000000600ae8 d __JCR_LIST__
0000000000600af0 d _DYNAMIC
0000000000600cf8 d _GLOBAL_OFFSET_TABLE_
0000000000600d50 D __data_start
0000000000600d50 W data_start
0000000000600d58 D __dso_handle
0000000000600d60 B __bss_start
0000000000600d60 D _edata
0000000000600d60 D __TMC_END__
0000000000600d60 B std::cout@@GLIBCXX_3.4
0000000000600e70 b completed.6392
0000000000600e71 b std::__ioinit
0000000000600e78 B _end

Although the source code for both C and C++ are as simple, C++ creates more complicated code linked to more libraries with mangled symbols.

Let’s look into how hello.cxx is compiled by stopping before the assembler by creating assembler code with the -S option and demangling it with c++filt -n.

$ g++ -S hello.cxx
$ c++filt -n <hello.s |fold
    .file    "hello.cxx"
    .local    std::__ioinit
    .comm    std::__ioinit,1,1
    .section    .rodata
.LC0:
    .string    "Hello World!"
    .text
    .globl    main
    .type    main, @function
main:
.LFB971:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $.LC0, %esi
    movl    std::cout, %edi
    call    std::basic_ostream<char, std::char_traits<char> >& std::operator
<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&,
 char const*)
    movl    std::basic_ostream<char, std::char_traits<char> >& std::endl<cha
r, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&),
 %esi
    movq    %rax, %rdi
    call    std::basic_ostream<char, std::char_traits<char> >::operator<<(st
d::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, st
d::char_traits<char> >&))
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE971:
    .size    main, .-main
    .type    __static_initialization_and_destruction_0(int, int), @function
__static_initialization_and_destruction_0(int, int):
.LFB980:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    cmpl    $1, -4(%rbp)
    jne    .L3
    cmpl    $65535, -8(%rbp)
    jne    .L3
    movl    std::__ioinit, %edi
    call    std::ios_base::Init::Init()
    movl    $__dso_handle, %edx
    movl    std::__ioinit, %esi
    movl    std::ios_base::Init::~Init(), %edi
    call    __cxa_atexit
.L3:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE980:
    .size    __static_initialization_and_destruction_0(int, int), .-__static_
initialization_and_destruction_0(int, int)
    .type    _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB981:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $65535, %esi
    movl    $1, %edi
    call    __static_initialization_and_destruction_0(int, int)
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE981:
    .size    _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
    .section    .init_array,"aw"
    .align 8
    .quad    _GLOBAL__sub_I_main
    .hidden    __dso_handle
    .ident    "GCC: (Debian 4.8.1-9) 4.8.1"
    .section    .note.GNU-stack,"",@progbits

For more on C++ ABI issues, see:

Vala

Simple non-OOP style (no class)

Source code hello-1.vala in Vala language

int main(string[] args) {
    stdout.printf("Hello, world!\n");
    return 0;
}

Let’s compile hello-1.vala to create the ELF object hello-1 and run it.

$ valac -v hello-1.vala
/path/to/vala/hello-1.vala.c: In function ‘main’:
/path/to/vala/hello-1.vala.c:28:2: warning: ‘g_type_init’ is deprecated (declared...
  g_type_init ();
  ^
Loaded package `/usr/share/vala-0.20/vapi/glib-2.0.vapi'
Loaded package `/usr/share/vala-0.20/vapi/gobject-2.0.vapi'
cc -o '/path/to/vala/hello-1' '/path/to/vala/hello-1.vala.c' -I/usr/include/glib-...
$ ./hello-1
Hello, world!

You can get the C source as:

$ valac -C hello-1.vala
$ wc -l hello-1.vala ; wc -l hello-1.c
4 hello-1.vala
33 hello-1.c
$ cat hello-1.c
/* hello-1.c generated by valac 0.20.1, the Vala compiler
 * generated from hello-1.vala, do not modify */


#include <glib.h>
#include <glib-object.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>




gint _vala_main (gchar** args, int args_length1);


gint _vala_main (gchar** args, int args_length1) {
    gint result = 0;
    FILE* _tmp0_;
    _tmp0_ = stdout;
    fprintf (_tmp0_, "Hello, world!\n");
    result = 0;
    return result;
}


int main (int argc, char ** argv) {
    g_type_init ();
    return _vala_main (argv, argc);
}



Since no OOP techniques are used, the resulting C code is logically as simple as the Vala code except for some #include directives to pertinent libraries automatically included for the Vala code.

OOP style (main outside of class)

Source code hello-2.vala in the Vala language

using GLib;
public class Demo.HelloWorld : GLib.Object {
    public int hello() {
        stdout.printf("Hello, world!\n");
        return 0;
    }
}

int main(string[] args) {
    var obj = new Demo.HelloWorld();
    obj.hello();
    return 0;
}

TIP: Since the use of GLib for the parent class is the default for Vala, the line of using GLib; and the prefix of GLib. in the above example may be dropped as an exception.

Let’s compile hello-2.vala to create the ELF object hello-2 and run it.

$ valac -v hello-2.vala
/path/to/vala/hello-2.vala.c: In function ‘main’:
/path/to/vala/hello-2.vala.c:104:2: warning: ‘g_type_init’ is deprecated (declare...
  g_type_init ();
  ^
Loaded package `/usr/share/vala-0.20/vapi/glib-2.0.vapi'
Loaded package `/usr/share/vala-0.20/vapi/gobject-2.0.vapi'
cc -o '/path/to/vala/hello-2' '/path/to/vala/hello-2.vala.c' -I/usr/include/glib-...
$ ./hello-2
Hello, world!

You can get the C source as:

$ valac -C hello-2.vala
$ wc -l hello-2.vala ; wc -l hello-2.c
13 hello-2.vala
109 hello-2.c
$ cat hello-2.c|sed -e 's/      /    /g'|fold # tab => 4 spaces
/* hello-2.c generated by valac 0.20.1, the Vala compiler
 * generated from hello-2.vala, do not modify */


#include <glib.h>
#include <glib-object.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define DEMO_TYPE_HELLO_WORLD (demo_hello_world_get_type ())
#define DEMO_HELLO_WORLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEMO_TYPE_HELL
O_WORLD, DemoHelloWorld))
#define DEMO_HELLO_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEMO_TY
PE_HELLO_WORLD, DemoHelloWorldClass))
#define DEMO_IS_HELLO_WORLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEMO_TYPE_H
ELLO_WORLD))
#define DEMO_IS_HELLO_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEMO
_TYPE_HELLO_WORLD))
#define DEMO_HELLO_WORLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEMO_
TYPE_HELLO_WORLD, DemoHelloWorldClass))

typedef struct _DemoHelloWorld DemoHelloWorld;
typedef struct _DemoHelloWorldClass DemoHelloWorldClass;
typedef struct _DemoHelloWorldPrivate DemoHelloWorldPrivate;
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (va
r), NULL)))

struct _DemoHelloWorld {
    GObject parent_instance;
    DemoHelloWorldPrivate * priv;
};

struct _DemoHelloWorldClass {
    GObjectClass parent_class;
};


static gpointer demo_hello_world_parent_class = NULL;

GType demo_hello_world_get_type (void) G_GNUC_CONST;
enum  {
    DEMO_HELLO_WORLD_DUMMY_PROPERTY
};
gint demo_hello_world_hello (DemoHelloWorld* self);
DemoHelloWorld* demo_hello_world_new (void);
DemoHelloWorld* demo_hello_world_construct (GType object_type);
gint _vala_main (gchar** args, int args_length1);


gint demo_hello_world_hello (DemoHelloWorld* self) {
    gint result = 0;
    FILE* _tmp0_;
    g_return_val_if_fail (self != NULL, 0);
    _tmp0_ = stdout;
    fprintf (_tmp0_, "Hello, world!\n");
    result = 0;
    return result;
}


DemoHelloWorld* demo_hello_world_construct (GType object_type) {
    DemoHelloWorld * self = NULL;
    self = (DemoHelloWorld*) g_object_new (object_type, NULL);
    return self;
}


DemoHelloWorld* demo_hello_world_new (void) {
    return demo_hello_world_construct (DEMO_TYPE_HELLO_WORLD);
}


static void demo_hello_world_class_init (DemoHelloWorldClass * klass) {
    demo_hello_world_parent_class = g_type_class_peek_parent (klass);
}


static void demo_hello_world_instance_init (DemoHelloWorld * self) {
}


GType demo_hello_world_get_type (void) {
    static volatile gsize demo_hello_world_type_id__volatile = 0;
    if (g_once_init_enter (&demo_hello_world_type_id__volatile)) {
        static const GTypeInfo g_define_type_info = { sizeof (DemoHelloWorldClas
s), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) demo_hello_
world_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (DemoHelloWorld), 0, (
GInstanceInitFunc) demo_hello_world_instance_init, NULL };
        GType demo_hello_world_type_id;
        demo_hello_world_type_id = g_type_register_static (G_TYPE_OBJECT, "DemoH
elloWorld", &g_define_type_info, 0);
        g_once_init_leave (&demo_hello_world_type_id__volatile, demo_hello_world
_type_id);
    }
    return demo_hello_world_type_id__volatile;
}


gint _vala_main (gchar** args, int args_length1) {
    gint result = 0;
    DemoHelloWorld* _tmp0_;
    DemoHelloWorld* obj;
    _tmp0_ = demo_hello_world_new ();
    obj = _tmp0_;
    demo_hello_world_hello (obj);
    result = 0;
    _g_object_unref0 (obj);
    return result;
}


int main (int argc, char ** argv) {
    g_type_init ();
    return _vala_main (argv, argc);
}



It is obvious Vala code is much shorter than C.

The Vala class definition of Demo.HelloWorld subclassed from GLib.Object are converted into the C code defining GObject with many macros. These C code macros are cliches to use GLib and GObject in C. The Vala compiler takes care these chores for you.

The instantiation of the obj object by the Vala new expression is converted into the C demo_hello_world_new() function which in turn calls the C demo_hello_world_construct() function. The dynamic memory management by the reference counting in the GLib is used to assign memory to the obj object.

The Vala also adds a wrapper macro _g_object_unref0(obj) to the C code which is required to free memory properly for the obj object.

In general, these macro cliches of GObject are defined as follows:

#define FOO_TYPE_BAR (foo_bar_get_type ()) #define FOO_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
FOO_TYPE_BAR, FooBar)) #define FOO_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
FOO_TYPE_BAR, FooBarClass)) #define FOO_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
FOO_TYPE_BAR)) #define FOO_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
FOO_TYPE_BAR)) #define FOO_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
FOO_TYPE_BAR, FooBarClass))

Here:

OOP style (main inside of class)

Source code hello-3.vala in the Vala language

using GLib;
public class Demo.HelloWorld : GLib.Object {
    private int hello() {
        stdout.printf("Hello, world!\n");
        return 0;
    }
    public static int main(string[] args) {
        var obj = new Demo.HelloWorld();
        obj.hello();
        return 0;
    }
}

TIP: Since the use of GLib for the parent class is the default for Vala, the line of using GLib; and the prefix of GLib. in the above example may be dropped as an exception.

Let’s compile hello-3.vala to create the ELF object hello-3 and run it.

$ valac -v hello-3.vala
/path/to/vala/hello-3.vala.c: In function ‘main’:
/path/to/vala/hello-3.vala.c:71:2: warning: ‘g_type_init’ is deprecated (declared...
  g_type_init ();
  ^
Loaded package `/usr/share/vala-0.20/vapi/glib-2.0.vapi'
Loaded package `/usr/share/vala-0.20/vapi/gobject-2.0.vapi'
cc -o '/path/to/vala/hello-3' '/path/to/vala/hello-3.vala.c' -I/usr/include/glib-...
$ ./hello-3
Hello, world!

You can get the C source as:

$ valac -C hello-3.vala
$ wc -l hello-3.vala ; wc -l hello-3.c
13 hello-3.vala
109 hello-3.c
$ cat hello-3.c|sed -e 's/      /    /g'|fold # tab => 4 spaces
/* hello-3.c generated by valac 0.20.1, the Vala compiler
 * generated from hello-3.vala, do not modify */


#include <glib.h>
#include <glib-object.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define DEMO_TYPE_HELLO_WORLD (demo_hello_world_get_type ())
#define DEMO_HELLO_WORLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEMO_TYPE_HELL
O_WORLD, DemoHelloWorld))
#define DEMO_HELLO_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEMO_TY
PE_HELLO_WORLD, DemoHelloWorldClass))
#define DEMO_IS_HELLO_WORLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEMO_TYPE_H
ELLO_WORLD))
#define DEMO_IS_HELLO_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEMO
_TYPE_HELLO_WORLD))
#define DEMO_HELLO_WORLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEMO_
TYPE_HELLO_WORLD, DemoHelloWorldClass))

typedef struct _DemoHelloWorld DemoHelloWorld;
typedef struct _DemoHelloWorldClass DemoHelloWorldClass;
typedef struct _DemoHelloWorldPrivate DemoHelloWorldPrivate;
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (va
r), NULL)))

struct _DemoHelloWorld {
    GObject parent_instance;
    DemoHelloWorldPrivate * priv;
};

struct _DemoHelloWorldClass {
    GObjectClass parent_class;
};


static gpointer demo_hello_world_parent_class = NULL;

GType demo_hello_world_get_type (void) G_GNUC_CONST;
enum  {
    DEMO_HELLO_WORLD_DUMMY_PROPERTY
};
static gint demo_hello_world_hello (DemoHelloWorld* self);
gint demo_hello_world_main (gchar** args, int args_length1);
DemoHelloWorld* demo_hello_world_new (void);
DemoHelloWorld* demo_hello_world_construct (GType object_type);


static gint demo_hello_world_hello (DemoHelloWorld* self) {
    gint result = 0;
    FILE* _tmp0_;
    g_return_val_if_fail (self != NULL, 0);
    _tmp0_ = stdout;
    fprintf (_tmp0_, "Hello, world!\n");
    result = 0;
    return result;
}


gint demo_hello_world_main (gchar** args, int args_length1) {
    gint result = 0;
    DemoHelloWorld* _tmp0_;
    DemoHelloWorld* obj;
    _tmp0_ = demo_hello_world_new ();
    obj = _tmp0_;
    demo_hello_world_hello (obj);
    result = 0;
    _g_object_unref0 (obj);
    return result;
}


int main (int argc, char ** argv) {
    g_type_init ();
    return demo_hello_world_main (argv, argc);
}


DemoHelloWorld* demo_hello_world_construct (GType object_type) {
    DemoHelloWorld * self = NULL;
    self = (DemoHelloWorld*) g_object_new (object_type, NULL);
    return self;
}


DemoHelloWorld* demo_hello_world_new (void) {
    return demo_hello_world_construct (DEMO_TYPE_HELLO_WORLD);
}


static void demo_hello_world_class_init (DemoHelloWorldClass * klass) {
    demo_hello_world_parent_class = g_type_class_peek_parent (klass);
}


static void demo_hello_world_instance_init (DemoHelloWorld * self) {
}


GType demo_hello_world_get_type (void) {
    static volatile gsize demo_hello_world_type_id__volatile = 0;
    if (g_once_init_enter (&demo_hello_world_type_id__volatile)) {
        static const GTypeInfo g_define_type_info = { sizeof (DemoHelloWorldClas
s), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) demo_hello_
world_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (DemoHelloWorld), 0, (
GInstanceInitFunc) demo_hello_world_instance_init, NULL };
        GType demo_hello_world_type_id;
        demo_hello_world_type_id = g_type_register_static (G_TYPE_OBJECT, "DemoH
elloWorld", &g_define_type_info, 0);
        g_once_init_leave (&demo_hello_world_type_id__volatile, demo_hello_world
_type_id);
    }
    return demo_hello_world_type_id__volatile;
}



It is obvious Vala code is much shorter than C. Many CPP macros are defined here, too. These are cliches to use GLib and GObject in C. The Vala compiler takes care these chores for you.

Previous Post Top Next Post