Autor Wątek: [Rozkminka] Jakim językiem programowania powinno się traktować początkujących.  (Przeczytany 22651 razy)

Offline draghan

  • Użytkownik

# Kwiecień 03, 2015, 16:13:38
Według mnie, wybór początkowego języka powinien zależeć od tego, czego chcemy się nauczyć.

Jeśli chcemy dopiero popróbować programowania, z czym to się je, jak to smakuje, to dobry język jest taki, który ma dużo tutoriali, dobrą dokumentację, nie jest skomplikowany składniowo, nie ma jakichś ukrytych sztuczek, które trzeba znać.
Python wygląda w tym względzie dobrze, chociaż mi osobiście nie przypadł do gustu.
Trochę ryzykownie postawiłbym też na Pascala - chociaż nie wiem, jak broni się taki staroć dziś. Sam od niego zaczynałem (ale że zostałem oczarowany, a niedługo później rozczarowany, przerzuciłem się na C++).

Jeśli zależy nam na nauczeniu się front-endu, to oczywiście w grę wchodzą jakieś technologie webowe, na początek HTML+CSS to jest must-have, do tego JavaScript.

Jeśli chcemy się specjalizować w np. programowaniu mikrokontrolerów, to należy chyba zacząć od C.

Wszystko zależy od naszych chęci i docelowego targetu. Chęci mogą być podsycane przez "zajawki", jak to ktoś napisał - jeśli widzimy, że można stworzyć coś fajnego, lepiej nam się uczy.

Ale moje zdanie klaruje się gdzieś na poziomie stwierdzenia, że początkowy język nie ma bardzo dużo do powiedzenia w nauce - o wiele więcej mają nasze chęci.
Znam chłopaka, który twierdzi, że ma pasję, że lubi kodować. A jak przychodzi co do czego, to się okazuje, że siada do kodu dwa razy na miesiąc i chce od razu umieć wszystko, nie znając podstaw. W takim przypadku to zostają mu tylko jakieś gotowe frameworki, broń bosze takie, gdzie samemu coś trzeba oskryptować. Python mu się nie spodobał, C++ nie spodobał się, próbował nawet ASMa...
A to tylko trzeba chcieć... ;)

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

  • +2
# Kwiecień 03, 2015, 17:15:56
Cytuj
Jeśli chcemy się specjalizować w np. programowaniu mikrokontrolerów, to należy chyba zacząć od C.
Dlaczego? Ja programowaniem mikrokontrolerów na chleb zarabiam i zdecydowanie wolę to robić w C++. :)

Ba... Arduino, które definitywnie mierzy w początkujących, jest oparte na C++.

Offline draghan

  • Użytkownik

# Kwiecień 03, 2015, 18:14:42
A widzisz, Krzysiek, za mało mam jeszcze doświadczenia akurat w tym temacie. ^^' Zaczynam studiować automatykę i robotykę i wykładowcy twierdzą, że C to główny język dla mikrokontrolerów. Także mogłem się pomylić, bo jeszcze nie miałem okazji tym się własnoręcznie pobawić.
Ale skoro w C++ też można, to tchnąłeś nadzieję w moje serce, bo lubię C, ale C++ jest lepszejsze. :P

Offline Xender

  • Użytkownik

# Kwiecień 03, 2015, 18:37:22
@up - Wiesz, takie Linusy to nawet twierdzą, że C jest lepsze na "dużych" architekturach.

Nie ma większych powodów, żeby nie dało się programować uC w C++.

Oczywiście gorzej może być z biblioteką standardową, ale sporo mechanizmów rdzenia C++, które ułatwiają robotę (zwykłe (nie-wirtualne) metody, RAII, templatki, auto), nie powoduje narzutu runtime, lub powoduje jedynie nieznaczny.

Chyba, że backend (lub inna część toolchainu) na dany uC nie jest zgodny z C++-owym frontendem GCC/Clanga/innego kompilatora, wtedy gorzej.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Kwiecień 03, 2015, 18:44:41
Cytuj
Zaczynam studiować automatykę i robotykę i wykładowcy twierdzą, że C to główny język dla mikrokontrolerów.
Weź poprawkę na to, że wykładowcy bardzo rzadko aktualizują materiały wykładowe i mogłeś trafić na takie sprzed 20 lat.

Cytuj
Ale skoro w C++ też można, to tchnąłeś nadzieję w moje serce, bo lubię C, ale C++ jest lepszejsze. :P
Większość mikrokontrolerów da się programować kompilując w GCC, więc sam język nie jest problemem. Za to jeżeli planujesz zaprząc ciężkiego OOPa, RAII i inne dziwolągi, to możesz się zdziwić jak szybko ci się miejsce w procku skończy. O ile nie zdziwisz się wcześniej, że biblioteki w standardzie wyglądają zupełnie inaczej i masz w niej niskopoziomowe IO, ale za to nie ma STL, czy choćby zwykłego new/delete (ale to nie przeszkadza, bo nie jest to potrzebne).

Cytuj
sporo mechanizmów rdzenia C++ (...) RAII
A od kiedy to RAII jest mechanizmem C++? To jest tylko i wyłącznie filozofia kodowania stosowalna w chyba każdym języku imperatywnym.

Inna kwestia że klasyczne podejście do RAII w C++ na uC słabo widzę, bo najczęściej tu nie masz new/delete ani nie masz wyjątków.

Cytuj
Chyba, że backend (lub inna część toolchainu) na dany uC nie jest zgodny z C++-owym frontendem GCC/Clanga/innego kompilatora, wtedy gorzej.
Jeszcze nie spotkałem się z kompilatorem, w którym backend i frontend składało by się ot tak przez użytkownika. Najczęściej dostajesz to w jednym exe i tyle. Poza tym backendy kompilatorów są z reguły kompletnie nieprzenaszalne pomiędzy różnymi kompilatorami.

Offline Xender

  • Użytkownik

  • +1
# Kwiecień 03, 2015, 19:00:32
A od kiedy to RAII jest mechanizmem C++? To jest tylko i wyłącznie filozofia kodowania stosowalna w chyba każdym języku imperatywnym.
RAII wymaga deterministycznie wywoływanych destruktorów.
Z języków, które znam, oferują to tylko C++ i D, oraz Python w implementacji CPython ("tej standardowej"), ale tylko, jeśli nie zrobisz sobie referencji cyklicznych (a jak zrobisz, to GC może Ci w ogóle takiego obiektu nie tknąć, więc to trochę proszenie się o kłopoty).

Jeszcze nie spotkałem się z kompilatorem, w którym backend i frontend składało by się ot tak przez użytkownika. Najczęściej dostajesz to w jednym exe i tyle.
Ale wiesz, że ta binarka woła tonę innych?
Włącznie z tym, że preprocesor jest osobną binarką.
Więc nie byłbym taki pewien, że parsowanie już przepreprocesowanego C++ (początek frontendu) i generowanie docelowego assembly lub kodu binarnego (końcówka backendu) dzieje się w jednej binarce...

Poza tym masz reprezentacją pośrednią - GENERIC/GIMPLE w GCC i LLVM-IR w LLVM.
I one są dokładnie po to, żeby można było sobie dobrać frontend do backendu.


Zresztą, nawet nie chodzi o to, jak dokładnie frontend gada z backendem.
Chodziło mi o to, że nie zawsze są ze sobą zgodne.
Bo np. nikomu się nie chciało zrobić tego exeka dla Ciebie, który kompilowałby C++ na daną architekturę.

Poza tym backendy kompilatorów są z reguły kompletnie nieprzenaszalne pomiędzy różnymi kompilatorami.
http://dragonegg.llvm.org/

Offline bies

  • Użytkownik

# Kwiecień 03, 2015, 19:21:24
RAII wymaga deterministycznie wywoływanych destruktorów.
Powiedzmy... Ale IMO to poniżej to też jest RAII a nie wymaga destruktorów w ogóle:
Kod: (File.xtend) [Zaznacz]
import java.io.BufferedWriter
import java.io.FileWriter

class File {
    def static writeFile(String name, (BufferedWriter)=>void lambda) {
        var BufferedWriter wr = null
        try {
            wr = new BufferedWriter(new FileWriter(name));
            lambda.apply(wr)
        }
        finally {
            wr?.close();
        }
    }
}
I użycie:
Kod: (Main.xtend) [Zaznacz]
import static File.writeFile

class Main {
    def static main(String[] args) {
        writeFile("out.txt") [
            write("Hello!")
        ]
    }       
}

Podobnie Java8 try-with-resources czy @Cleanup z Lombok. To też jest przeniesiona idea RAII na język bez destruktorów.

// edit
W ogóle mam wrażenie, że ludzie od tzw. ,,nowoczesnych języków programowania'' zaczynają zauważać, że jest coś więcej niż pamięć. Javie to zajęło prawie 20 lat...
« Ostatnia zmiana: Kwiecień 03, 2015, 19:34:19 wysłana przez bies »

Offline Xender

  • Użytkownik

# Kwiecień 03, 2015, 20:13:42
@bies - OK, zapomniałem o "with" i podobnych (a nie powinienem, bo z with w Pythonie korzystam, gdzie się da o_O).

Ok, w takim razie Python i par innych języków.
Ale to nadal nie "wszystkie imperatywne".

Funkcja, która przyjmuje callback, i explicite zajmuje się zasobami, przekazując je callbackowi to taka emulacja RAII.
To, że callback ma postać lambdy, czyni cały interes bardziej używalnym.
W sumie dobrze zrobione, może niczym nie ustępować RAII na destruktorach lub specjalnych metodach wołanych przez składnię "with" (a może nawet pozwoli na zaemulowanie generycznego "with"). Spoko.

Offline rafal3920

  • Użytkownik

# Kwiecień 04, 2015, 17:22:33
Mikrokoltrolery bez problemu programuje się przy użyciu C++, Atmel Studio 6 ma taką opcję

Offline Xender

  • Użytkownik

# Kwiecień 04, 2015, 17:33:10
@rafal3920 - AVR to konkretna rodzina uC konkretnego producenta, a nie generyczny synonim słowa uC.

Innymi słowy: jest wiele różnych rodzin uC i nie mam pojęcia o tym, czy na wszystkie istnieją toolchainy C++.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Kwiecień 04, 2015, 17:43:38
Cytuj
AVR to konkretna rodzina uC konkretnego producenta, a nie generyczny synonim słowa uC.
Dlaczego od razu AVR? Atmel Studio kompiluje też na ARMy, które są już mocno popularne od wielu producentów (Atmel, ST, NXP i pewnie jeszcze kupa innych).

Cytuj
Innymi słowy: jest wiele różnych rodzin uC i nie mam pojęcia o tym, czy na wszystkie istnieją toolchainy C++.
AVR: jak wyżej, plus Arduino
ARM: cały świat pisze na to w C++ (fony)
PIC: coś tam jest od Microchipa oraz IAR
8051: Ceibo - płatne, ale jest

Tyle przynajmniej znam z tych najpopularniejszych. Poza tym są jeszcze konwertery z C++ na C, więc jak się uprzesz, to się da prawie na wszystkim.

Offline Xion

  • Moderator
    • xion.log

  • +1
# Kwiecień 04, 2015, 21:04:48
Cytuj
Ale IMO to poniżej to też jest RAII (...)
Nie. RAII jest techniką polegającą na wykorzystaniu procesu odwijania stosu i wywoływania destruktorów zmiennych lokalnych. Ze znanych mi języków tylko C++ ma rzeczone odwijanie. W Pythonie, Javie, C#, Go, itp. mamy po prostu jawne zarządzanie zasobami, z ich pozyskiwaniem i zwalnianiem. Swoją drogą daje to ciekawy efekt: dzięki RAII, w  C++ nie ma różnicy między pamięcią a innymi zasobami - w odróżnieniu od innych języków, gdzie pamięć jest zarządzana w większości automatycznie, ale np. deskryptory plikowe trzeba jawnie pozyskiwać i zwalniać.

Offline ArekBal

  • Użytkownik

# Kwiecień 04, 2015, 21:47:39
Kod: (c#) [Zaznacz]
public class Me
    {
       ~Me()
      {
        Console.WriteLine("destroy");
      }
    }
 class Program
  {
    static void Main(string[] args)
    {
      var me = new Me();
    }
  }
W praktyce używa się "using" + IDisposable,  bo to czy ten destruktor wywoła się przy zwijaniu stosu będzie zależeć od jego "zależności"(LOL).
Nie jest to, to samo co C++ ale twoja definicja się połamie.
« Ostatnia zmiana: Kwiecień 04, 2015, 21:53:01 wysłana przez ArekBal »

Offline Xender

  • Użytkownik

  • +1
# Kwiecień 04, 2015, 22:27:20
Nie jest to, to samo co C++ ale twoja definicja się połamie.
W którym miejscu?
Mowa była o destruktorach wywoływanych deterministycznie przy odwijaniu* stosu, a nie o finalizerach wołanych w bliżej nieokreślonym czasie, gdy GC zbierze obiekt.

Składnia podobna, ale to tyle.

* Przy okazji: Czy opuszczanie ramki stosu w wyniku zwykłego return, a nie wyjątku, ma jakąś specjalną nazwę?

Offline ArekBal

  • Użytkownik

# Kwiecień 04, 2015, 22:54:41
Nie są to destruktory, a funkcjonalność "odwijania stosu" jest realizowana przez IDiposable o czym wspomniałem.

Cytuj
destruktorach wywoływanych deterministycznie przy odwijaniu* stosu
nie wiesz co determinizm :(
Cytuj
finalizerach wołanych w bliżej nieokreślonym czasie, gdy GC zbierze obiekt.
Reguły GC są znane, więc żadnego "nieokreślonego" czasu tu nie ma.