Skip to content

Type-casting issue when providing a generic function as argument. #21132

Closed

Description

@debilosaurus

Describe the bug

I am not 100% shure if this is bug, but I am not able to create a function with another function (from a std library) as argument. In my opinion this should work, but everything I tried didnt. Ths snipped is the most basic one. I tried with setting the generic to "f64" (the error message than refers surprisingly to the module like "math.f64"), or try to cast the function type (more errors of course).

I hope that I have made a mistake, but this type of functions would be very helpfull to avoid unnecessary (escecially for lazy people like me).

Reproduction Steps

Code: https://play.vlang.io/p/0a82f72d9f

// function-as-argument to reduce code

import math

type Vec5 = struct {
	x f64
	y f64
	z f64
	a f64
	b f64
}

fn from(s f64) Vec5 {
	return Vec5{s, s, s, s, s}
}

fn (v Vec5) abs_oldstyle() Vec5 {
	return Vec5{math.abs(v.x), math.abs(v.y), math.abs(v.z), math.abs(v.a), math.abs(v.b)}
}

fn (v Vec5) generic_new(f fn (f64) f64) Vec5 {
	return Vec5{f(v.x), f(v.y), f(v.z), f(v.a), f(v.b)}
}

fn main() {
	println('### start')

	mut v := from(-1)
	println(v)
	println(v.abs_oldstyle()) // ok
	// error: cannot use `fn (T) T` as `fn (f64) f64` in argument 1 to `Vec5.generic`
	println(v.generic_new(math.abs)) // error

	println('### end')
}

Expected Behavior

No error and the same result for "abs_oldstyle()" and "generic_new(math.abs)".

Current Behavior

Output:

code.v:32:23: error: cannot use `fn (T) T` as `fn (f64) f64` in argument 1 to `Vec5.generic_new`
   30 |     println(v.abs_oldstyle()) // ok
   31 |     // error: cannot use `fn (T) T` as `fn (f64) f64` in argument 1 to `Vec5.generic`
   32 |     println(v.generic_new(math.abs)) // error
      |                          ~~~~~~~~
   33 | 
   34 |     println('### end')
Exited with error status 1

Possible Solution

No response

Additional Information/Context

No response

V version

V 0.4.5 872bcbc

Environment details (OS name and version, etc.)

V full version: V 0.4.5 872bcbc
OS: linux, Debian GNU/Linux 11 (bullseye) (VM)
Processor: 1 cpus, 64bit, little endian, Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz

getwd: /home/admin/playground
vexe: /home/admin/v/v
vexe mtime: 2024-03-28 12:23:26

vroot: OK, value: /home/admin/v
VMODULES: OK, value: .vmodules
VTMP: OK, value: /tmp/v_0

Git version: git version 2.30.2
Git vroot status: Error: fatal: detected dubious ownership in repository at '/home/admin/v'
To add an exception for this directory, call:

	git config --global --add safe.directory /home/admin/v
.git/config present: true

CC version: cc (Debian 10.2.1-6) 10.2.1 20210110
thirdparty/tcc status: Error: fatal: detected dubious ownership in repository at '/home/admin/v/thirdparty/tcc'
To add an exception for this directory, call:

	git config --global --add safe.directory /home/admin/v/thirdparty/tcc
 Error: fatal: detected dubious ownership in repository at '/home/admin/v/thirdparty/tcc'
To add an exception for this directory, call:

	git config --global --add safe.directory /home/admin/v/thirdparty/tcc

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

Activity

  1. added
    BugThis tag is applied to issues which reports bugs.
    on Mar 28, 2024
  2. debilosaurus commented on Mar 29, 2024

    @debilosaurus
    Author

    I have found a fix, but I am still thinking that some "autocast" feature dont work properly:

    Change:

    println(v.generic_new(math.abs)) // error

    To:

    math_abs := fn (s f64) f64 { return math.abs(s) }
    println(v.generic_new(math_abs)) // fix with new function
  3. debilosaurus commented on Mar 30, 2024

    @debilosaurus
    Author

    Again: This is no priority bug, maybe it isn't an issue at all.
    But here is another hint why I think that there must be casting issues; this time with an interface type.

    Backround: For testing purposes with signed distance functions I wrote my own vector implementation. Then I tried to reduce the code to the absolute minimum - with interfaces . my goal is to generalize it in a simple way to more dimensions or other implementations (eg. array). But vlang sometimes is a beast ...

    // vlang test, reduced for git:
    // - vector operations (example) build with an interface
    // - derive functions for a group of basic types
    // questions:
    // - how to use interface methods withou an additional cast
    // - where are casts or generic types missing
    
    module main
    
    // scalar, basic type
    type Scalar = f64
    
    // basic function, not build as method, needed as arg
    fn add_scalar(s1 Scalar, s2 Scalar) Scalar {
    	return s1 + s2
    }
    
    // vector, interface an derived functions
    interface Vector {
    	libs (fn (Scalar, Scalar) Scalar) Scalar
    //	lib2 (Vector, fn (Scalar, Scalar) Scalar) Vector
    }
    
    // derived method 1
    fn (v Vector) sum() Scalar {
    	return v.libs(add_scalar)
    }
    
    /* // derived method 2
    fn (v1 Vector) add(v2 Vector) Vector {
    	return v1.lib2(v2, add_scalar)
    }
    */
    
    // vec3, representation of the interface
    type Vec3 = struct {
    	x Scalar
    	y Scalar
    	z Scalar
    }
    
    // basic method a, safisfies the interface type
    fn (v Vec3) libs(f fn (Scalar, Scalar) Scalar) Scalar {
    	return f(v.x, f(v.y, v.z))
    }
    
    /* // interface method b, safisfies the interface type
    fn (v1 Vec3) lib2(v2 Vec3, f fn (Scalar, Scalar) Scalar) Vec3 {
    //fn (v1 Vec3) lib2(v2 Vector, f fn (Scalar, Scalar) Scalar) Vector {
    	return Vec3{f(v1.x, v2.x), f(v1.y, v2.y), f(v1.z, v2.z)}
    }
    */
    
    fn main() {
    	println('### start')
    	
    	// define a vector
    	v := Vec3{1, 2, 3}
    	
    	// check if "Vec3" satifies the interface "Vector" -> ok
    	println(Vector(v))
    	
    	// try method of type with fn as arg -> ok
    	println(v.libs(add_scalar))
    	
    	// try methods of interface -> explicit cast needed, why?
    //	println(v.sum()) // should work
    	println(Vector(v).sum()) // but only works with a cast
    	
    	// try methods of interface -> error
    	// - "Vec3" as args produce "unknown method Vec3.sum/add"
    	// - "Vector" as args produce "no field name x/y/z"	
    //	println(v.add(v))
    	
    	// the goal, concat
    //	println(v.add(v).add(v))
    	
    	println('### end')
    }
  4. changed the title [-]Type-casting issue when providing a function as argument.[/-] [+]Type-casting issue when providing a generic function as argument.[/+] on Mar 31, 2024
  5. added
    Generics[T]Bugs/feature requests, that are related to the V generics.
    Unit: CheckerBugs/feature requests, that are related to the type checker.
    Unit: CompilerBugs/feature requests, that are related to the V compiler in general.
    Status: ConfirmedThis bug has been confirmed to be valid by a contributor.
    on Mar 31, 2024
  6. debilosaurus commented on Nov 10, 2024

    @debilosaurus
    Author

    After some time spending to other things, I tried to find the cause of this behavior. I hope this helps to improve your language.

    // vlang test, reduced for git:
    // - vector operations (example) build with an interface
    // - derive functions for a group of basic types
    // questions/problems:
    // - the compiler assumes initially that a type dont satisfies an interface,
    //   and so he cant solve references to the type itself
    // - interface methods should work without an additional cast
    
    module main
    
    // scalar, basic type
    type Scalar = f64
    
    // basic function, not build as method, needed as arg
    fn add_scalar(s1 Scalar, s2 Scalar) Scalar {
    	return s1 + s2
    }
    
    // vector, interface and derived functions
    interface Vector {
        elem (int) Scalar // dependency of an additional method
    	libs (fn (Scalar, Scalar) Scalar) Scalar
    	lib2 (Vector, fn (Scalar, Scalar) Scalar) Vector
    }
    
    // derived method 1
    fn (v Vector) sum() Scalar {
    	return v.libs(add_scalar)
    }
    
    // derived method 2
    fn (v1 Vector) add(v2 Vector) Vector {
    	return v1.lib2(v2, add_scalar)
    }
    
    // vec3, representation of the interface
    //type Vec3 = struct { // syntax change?
    struct Vec3 {
    	x Scalar
    	y Scalar
    	z Scalar
    }
    
    // problem 1: additional method needed, because v assumes a "not-satisfying"
    fn (v Vec3) elem(i int) Scalar {
       if i == 1 { return v.x }
       if i == 2 { return v.y }
       if i == 3 { return v.z }
       return Scalar(0.0)
    }
    // basic method a, safisfies the interface type
    fn (v Vec3) libs(f fn (Scalar, Scalar) Scalar) Scalar {
    	return f(v.x, f(v.y, v.z))
    }
    
    // interface method b, safisfies the interface type
    //fn (v1 Vec3) lib2(v2 Vec3, f fn (Scalar, Scalar) Scalar) Vec3 {
    //fn (v1 Vec3) lib2(v2 Vec3, f fn (Scalar, Scalar) Scalar) Vector {
    fn (v1 Vec3) lib2(v2 Vector, f fn (Scalar, Scalar) Scalar) Vector {
    	// this failes, because it is assumed that it does NOT satisfies the interface
    	//return Vec3{f(v1.x, v2.x), f(v1.y, v2.y), f(v1.z, v2.z)}
    	// so a function is needed, even if we know how to address the elements for this type
    	return Vec3{f(v1.elem(1), v2.elem(1)), f(v1.elem(2), v2.elem(2)), f(v1.elem(3), v2.elem(3))}
    }
    
    fn main() {
    	println('### start')
    	
    	// define a vector
    	v := Vec3{1, 2, 3}
    	
    	// check if "Vec3" satifies the interface "Vector" -> ok
    	println(Vector(v))
    	
    	// try method of type with fn as arg -> ok
    	println(v.libs(add_scalar))
    	
    	// try methods of interface -> explicit cast needed, why?
    //	println(v.sum()) // should work
    	println(Vector(v).sum()) // problem 2: only works with a cast
    	
    	// try methods of interface -> error
    	// - "Vec3" as args produce "unknown method Vec3.sum/add"
    	// - "Vector" as args produce "no field name x/y/z"	
    //	println(v.add(v)) // should work
    	println(Vector(v).add(v)) // problem 2: only works with a cast
    	
    	// the goal, concat/mix own/derived methods
    //	println(v.add(v).add(v)) // should work
    	println(Vector(v).add(v).add(v)) // problem 2: only works with a cast
    	
    	println('### end')
    }
  7. added 3 commits that reference this issue on Mar 25, 2026
    e3c5aba
    8ecc15f
    6811e86
  8. added a commit that references this issue on Apr 2, 2026
    82ba944
  9. added 4 commits that reference this issue on Apr 4, 2026
    49e0bea
    0d65e46
    15d42da
    f1ee2cb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugThis tag is applied to issues which reports bugs.Generics[T]Bugs/feature requests, that are related to the V generics.Status: ConfirmedThis bug has been confirmed to be valid by a contributor.Unit: CheckerBugs/feature requests, that are related to the type checker.Unit: CompilerBugs/feature requests, that are related to the V compiler in general.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions