this happens a lot, I want to find out how something works but I don’t know the said programming language and so I can’t read the source code, I’ve tried looking up stuff in cheatsheets but they don’t really help that much and Search Engines are obviously useless for this since they can’t search symbols, so how do you read the source code without spending time learning the language ?

  • @ttmrichter
    link
    61 year ago

    Learn more languages, especially cross-paradigm. Most languages in a given paradigm will be sufficiently similar that you can get the gist of any code written in it if you’re familiar with another language of the paradigm, especially if the code is reasonably written. For example:

    (specification)

    generic
       type Element_Type is private;
       type Index is (<>);
       type Collection is array(Index) of Element_Type;
       with function "<=" (Left, Right : Element_Type) return Boolean is <>;
    procedure Gnome_Sort(Item : in out Collection);
    

    (body)

    procedure Gnome_Sort(Item : in out Collection) is
       procedure Swap(Left, Right : in out Element_Type) is
          Temp : Element_Type := Left;
       begin
          Left := Right;
          Right := Temp;
       end Swap;
       
       I : Integer := Index'Pos(Index'Succ(Index'First));
       J : Integer := I + 1;
    begin
       while I <= Index'Pos(Index'Last) loop
          if Item(Index'Val(I - 1)) <= Item(Index'Val(I)) then
             I := J;
             J := J + 1;
          else
             Swap(Item(Index'Val(I - 1)), Item(Index'Val(I)));
             I := I - 1;
             if I = Index'Pos(Index'First) then
                I := J;
                J := J + 1;
             end if;
          end if;
       end loop;
    end Gnome_Sort;
    

    There’s a gnome sort (a.k.a. stupid sort) in Ada. If you’re familiar with any loosely structured-imperative programming language you can pretty much figure it out. while works as you’d likely expect. if and else too. loop and end loop and end if and even begin/end are pretty obvious. You’ll have to do a bit of head-scratching if you’re not familiar with languages in the Wirthian tradition (Pascal, the Modulas, the Oberons) to figure out which parts you can safely ignore and which parts you need to pay attention to, but it’s not really difficult. The hardest part is “weird” expressions like Index'Pos(Index'Succ(Index'First)); which you can still kind of guess the meaning of from context, especially in the later expression while I <= Index'Pos(Index'Last) where you might think Index`Pos() is like index.pos() in another language like Python or C++ and won’t be completely wrong (though still wrong).

    Basically you work it out by knowing the paradigm and knowing how things are generally expressed in said paradigm.

    Of course if you’re unfamiliar with the paradigm involved you might find it impossible to decode:

    (Erlang—functional)

    gnome(L, []) -> L;
    gnome([Prev|P], [Next|N]) when Next > Prev ->
    	gnome(P, [Next|[Prev|N]]);
    gnome(P, [Next|N]) ->
    	gnome([Next|P], N).
    gnome([H|T]) -> gnome([H], T).
    

    If you know another functional language like SML or Haskell or the like, this will be easy enough to read. Even if you know some logic languages like Prolog this is simple enough to follow. If you only know imperative languages (unstructured, structured, OOP, etc.), however, this will be gibberish.

    (Forth—concatenative)

    defer precedes
    defer exchange
    
    : gnomesort                            ( a n)
      swap >r 2 tuck 1-                    ( c2 n c1)
      begin                                ( c2 n c1)
        over over >                        ( c2 n c1 f)
      while                                ( c2 n c1)
        dup if                             ( c2 n c1)
          dup dup 1- over over r@ precedes
          if r@ exchange 1- else drop drop drop >r dup 1+ swap r> swap then
        else drop >r dup 1+ swap r> swap then
      repeat drop drop drop r> drop
    ;      
    
    :noname >r cells r@ + @ swap cells r> + @ swap < ; is precedes
    :noname >r cells r@ + swap cells r> + over @ over @ swap rot ! swap ! ; is exchange
    

    Although Forth is technically an imperative language, it is a very weird one with its stack discipline and unless you know it, or know related concatenative languages like Factor, this is going to be totally brain-damaging.

    So in cases where you’re unfamiliar with the paradigms involved: learn the paradigms. You should learn a new paradigm of programming every couple of years if you’re a serious programmer, after all.

    • @IcarusOP
      link
      11 year ago

      I see Thanks, I’ll learn more paradigms

      The hardest part is “weird” expressions like Index'Pos(Index'Succ(Index'First));

      Yes! this is exactly what I mean.

      • @ttmrichter
        link
        41 year ago

        OK, let’s take that weird one apart so I can show you the strategy for reasoning about it: Index'Pos(Index'Succ(Index'First));

        First, Index'Pos is clearly separating two lexical items: Index and Pos. Where have we seen either of those before? Pos is only ever used on the right hand side of ', so that’s a clue that this is some kind of component of Index. Index is defined, however. Let’s take a look at that specification again.

        generic
           type Element_Type is private;
           type Index is (<>);
           type Collection is array(Index) of Element_Type;
           with function "<=" (Left, Right : Element_Type) return Boolean is <>;
        procedure Gnome_Sort(Item : in out Collection);
        

        Index is a type. What type? (<>). That’s just gibberish if you only know Python and C, but we can still tease out some information.

        First, Index has a name that means something. It’s, well, an index. And if we look at Collection right underneath it, it’s an index into an array. So Index is likely an integer.

        So 'Pos is some kind of operation or member or something on the type of an integer. And it suggests that it means some kind of position. What could “position” mean to an integer?

        The clue lies in how the function there gets used. I didn’t put it there (because I was already being long-winded) but here’s the example of using that:

        with Gnome_Sort;
        with Ada.Text_Io; use Ada.Text_Io;
        
        procedure Gnome_Sort_Test is
           type Index is range 0..9;
           type Buf is array(Index) of Integer;
           procedure Sort is new Gnome_Sort(Integer, Index, Buf);
           A : Buf := (900, 700, 800, 600, 400, 500, 200, 100, 300, 0);
        begin
           for I in A'range loop
              Put(Integer'Image(A(I)));
           end loop;
           New_Line;
           Sort(A);
           for I in A'range loop
              Put(Integer'Image(A(I)));
           end loop;
           New_Line;
        end Gnome_Sort_Test;
        

        And here the penny drops. The Gnome_Sort routine is generic (clue: generic in the specification). The index has to be defined for it. We do that with the three lines immediately after the procedure line in the use case. Index is an integer in the range of 0…9.

        Because the Gnome_Sort procedure is generic, we make no assumptions about what the array ranges are: here it’s 0…9, but it could just as easily have been -1277516794231…125164987325159876. So these 'Pos, 'First, and 'Last and 'Val and such things are used to step through loops in a type-safe way that’s guaranteed to never step out of the array boundaries.

        But it’s largely unimportant. These are Ada-isms focused on Ada’s obsession: correctness. That’s just line noise, really, for purposes of understanding the code. We can kind of intuit that I is starting from the successor ('Succ) of the first ('First) (a.k.a the second) element of the array and going through it until it reaches the end of it (<= Index'Last). This guess is further bolstered by the comparison of things indexed via I - 1 against I.

        Decoding this is a dollop of familiarity with paradigms and coding approaches and decent contextual guessing. Is it better to just know the language? Yep. But even not knowing it you can tease out everything you need to work out how a gnome sort works. Part of the skill set in reading alien code is to learn how to relax and gloss over the bits that you don’t understand until you see the shape of the whole thing, after which, if you’re familiar with the paradigm, you can start making very good guesses as to what the unfamiliar bits actually mean. (Again, if you’re unfamiliar with the paradigm you’re … going to need to learn.)