V: Compiler handles array passing to functions wrongly.

Created on 24 Jul 2019  Â·  5Comments  Â·  Source: vlang/v

V version: V 0.1.16
OS: (Arch) Linux

What did you do?
I wrote bubblesort as followes:

fn bubblesort(arr mut []int) {
    for i := 0; i < arr.len-1; i++ {
        for j := 0; j < arr.len-i-1; j++ {
            if arr[j] > arr[j+1] {
                tmp := arr[j]
                arr[j] = arr[j+1]
                arr[j+1] = tmp
            }
        }
    }
}

fn main() {
    mut arr := [1, 45, 756, 4569, 56, 3, 8, 5, -10, -4]
    println('Array unsorted:')
    println(arr)
    bubblesort(mut arr)
    println('Array sorted:')
    println(arr)
}

What did you expect to see?
This should compile to a binary and work as expected.

What did you see instead?
The following warnings:

.bubble_sort.c: In function ‘bubblesort’:
.bubble_sort.c:2990:29: error: incompatible type for argument 1 of ‘array__get’
 2990 |  if ( ( *(int*) array__get( arr , j) ) > ( *(int*) array__get( arr , j + 1) ) ) {
      |                             ^~~
      |                             |
      |                             array_int * {aka struct array *}
.bubble_sort.c:369:25: note: expected ‘array’ {aka ‘struct array’} but argument is of type ‘array_int *’ {aka ‘struct array *’}
  369 |  void* array__get(array a, int i) {
      |                   ~~~~~~^
.bubble_sort.c:2990:64: error: incompatible type for argument 1 of ‘array__get’
 2990 |  if ( ( *(int*) array__get( arr , j) ) > ( *(int*) array__get( arr , j + 1) ) ) {
      |                                                                ^~~
      |                                                                |
      |                                                                array_int * {aka struct array *}
.bubble_sort.c:369:25: note: expected ‘array’ {aka ‘struct array’} but argument is of type ‘array_int *’ {aka ‘struct array *’}
  369 |  void* array__get(array a, int i) {
      |                   ~~~~~~^
.bubble_sort.c:2992:32: error: incompatible type for argument 1 of ‘array__get’
 2992 | int tmp= ( *(int*) array__get( arr , j) ) ;
      |                                ^~~
      |                                |
      |                                array_int * {aka struct array *}
.bubble_sort.c:369:25: note: expected ‘array’ {aka ‘struct array’} but argument is of type ‘array_int *’ {aka ‘struct array *’}
  369 |  void* array__get(array a, int i) {
      |                   ~~~~~~^
.bubble_sort.c:2994:37: error: incompatible type for argument 1 of ‘array__get’
 2994 |  int tmp12 =  ( *(int*) array__get( arr , j + 1) );
      |                                     ^~~
      |                                     |
      |                                     array_int * {aka struct array *}
.bubble_sort.c:369:25: note: expected ‘array’ {aka ‘struct array’} but argument is of type ‘array_int *’ {aka ‘struct array *’}
  369 |  void* array__get(array a, int i) {
      |                   ~~~~~~^
V panic: clang error

* The Problem *
As the errors state the first element of array__get is wrong. In case of arrays they are pointers and thus have to be dereferenced first.
Current C Code:

void bubblesort(array_int* arr) {
    for (int i= 0  ;  i < arr ->len - 1  ;  i ++ ) { 
        for (int j= 0  ;  j < arr ->len - i - 1  ;  j ++ ) { 
            if ( ( *(int*) array__get( arr , j) ) > ( *(int*) array__get( arr , j + 1) ) ) {
                int tmp= ( *(int*) array__get( arr , j) ) ;
                int tmp12 =  ( *(int*) array__get( arr , j + 1) ); 
                array_set( arr , j , & tmp12) ;
                int tmp13 =  tmp; 
                array_set( arr , j + 1 , & tmp13) ;
            };
        };
    };
}

Expected C Code:

void bubblesort(array_int* arr) {
    for (int i= 0  ;  i < arr ->len - 1  ;  i ++ ) { 
        for (int j= 0  ;  j < arr ->len - i - 1  ;  j ++ ) { 
            if ( ( *(int*) array__get( *arr , j) ) > ( *(int*) array__get( *arr , j + 1) ) ) {
                int tmp= ( *(int*) array__get( *arr , j) ) ;
                int tmp12 =  ( *(int*) array__get( *arr , j + 1) ); 
                array_set( arr , j , & tmp12) ;
                int tmp13 =  tmp; 
                array_set( arr , j + 1 , & tmp13) ;
            };
        };
    };
}

Note that in the corrected version arr is dereferenced in the array__get method.

Bug

Most helpful comment

I'm working on a fix right now.

All 5 comments

hi @Liikt, I _think_ because currently you don't have pass built in types with mut, so the extra mut is making it a reference. (I don't think this is the correct behavior, I think this is still being worked) but no error with:

fn bubblesort(arr []int) {
    for i := 0; i < arr.len-1; i++ {
        for j := 0; j < arr.len-i-1; j++ {
            if arr[j] > arr[j+1] {
                tmp := arr[j]
                arr[j] = arr[j+1]
                arr[j+1] = tmp
            }
        }
    }
}

fn main() {
    mut arr := [1, 45, 756, 4569, 56, 3, 8, 5, -10, -4]
    println('Array unsorted:')
    println(arr)
    bubblesort(arr)
    println('Array sorted:')
    println(arr)
}

I have same problem #1282

I'm working on a fix right now.

I was following the docs which have this example

fn multiply_by_2(arr mut []int) {
    for i := 0; i < arr.len; i++ {
        arr[i] *= 2
    }
}

mut nums := [1, 2, 3]
multiply_by_2(mut nums)
println(nums) // ==> "[2, 4, 6]"

I guess this is the same issue

Fixed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ArcDrake picture ArcDrake  Â·  3Comments

cjmxp picture cjmxp  Â·  3Comments

aurora picture aurora  Â·  3Comments

medvednikov picture medvednikov  Â·  3Comments

choleraehyq picture choleraehyq  Â·  3Comments