Skip to content

ValueGetter is not supported inmap #886

Open

Description

@veezhang

ValueGetter is not supported inmap:

https://go.dev/play/p/cutaKAgIxHj

package main

import (
	"fmt"

	"github.com/expr-lang/expr"
	"github.com/expr-lang/expr/patcher/value"
	"github.com/expr-lang/expr/vm"
)

type customInt struct {
	Int int
}

func (v *customInt) AsInt() int {
	return v.Int
}

func (v *customInt) AsAny() any {
	return v.Int
}

func main() {
	env := map[string]any{
		"params": map[string]any{
			"ValueOne": &customInt{1},
			"ValueTwo": &customInt{2},
		},
	}

	program, err := expr.Compile(
		"params.ValueOne + params.ValueTwo",
		expr.Env(env), 
		value.ValueGetter,
	)
	if err != nil {
		fmt.Println(err)
		return
	}

	out, err := vm.Run(program, env)
	if err != nil {
		panic(err)
	}

	fmt.Println(out)
}

The code above produced the following error:

panic: invalid operation: main.customInt + main.customInt (1:17)
	 | params.ValueOne + params.ValueTwo
	 | ................^

goroutine 1 [running]:
main.main()
	/tmp/sandbox3933238168/prog.go:43 +0x249

Program exited.

In my scenario, it's not possible to define a specific struct. Is there any way to solve this problem?

Activity

  1. antonmedv commented on Dec 22, 2025

    @antonmedv
    Member

    Why do you need to use a value getter?

  2. veezhang commented on Dec 23, 2025

    @veezhang
    Author

    Why do you need to use a value getter?

    I have defined a generic type for params, I wang use params.{key} nor params.{key}.Value() in expr.

    type(
    	ParamValue struct {
    		typ       ParamType
    		boolVal   bool
    		intVal    int
    		floatVal  float64
    		stringVal string
    		arrayVal  []*ParamValue
    		objectVal map[string]*ParamValue
    	}
    )
    
    func (v *ParamValue) Value() any {
    	switch v.typ {
    	case ParamTypeBool:
    		return v.boolVal
    	case ParamTypeInt:
    		return v.intVal
    	case ParamTypeFloat:
    		return v.floatVal
    	case ParamTypeString:
    		return v.stringVal
    	case ParamTypeArray:
    		return v.arrayVal
    	case ParamTypeObject:
    		return v.objectVal
    	default:
    		return nil
    	}
    }
    
    func (v ParamValue) AsAny() any {
    	return v.Value()
    }
  3. veezhang commented on Dec 23, 2025

    @veezhang
    Author

    This isn't the only example; ValueGetter is used in other places as well.
    We found that it doesn't work in nested maps, but it works in top-level maps.

  4. antonmedv commented on Dec 25, 2025

    @antonmedv
    Member

    Yes, valuegetter is not part of default expr default behaviour. I regret merging it actually. But why do you need those custom param containers in a first place?

  5. veezhang commented on Jan 8, 2026

    @veezhang
    Author

    Why do you need to use a value getter?

    I have defined a generic type for params, I wang use params.{key} nor params.{key}.Value() in expr.

    type(
    ParamValue struct {
    typ ParamType
    boolVal bool
    intVal int
    floatVal float64
    stringVal string
    arrayVal []*ParamValue
    objectVal map[string]*ParamValue
    }
    )

    func (v *ParamValue) Value() any {
    switch v.typ {
    case ParamTypeBool:
    return v.boolVal
    case ParamTypeInt:
    return v.intVal
    case ParamTypeFloat:
    return v.floatVal
    case ParamTypeString:
    return v.stringVal
    case ParamTypeArray:
    return v.arrayVal
    case ParamTypeObject:
    return v.objectVal
    default:
    return nil
    }
    }

    func (v ParamValue) AsAny() any {
    return v.Value()
    }

    I'm truly sorry for the delay in replying to you.

    For example, here I can use the more concise params.name1 and params.name1.name2 instead of params.name1.Value(), params.name1.Value().name2.Value().

  6. antonmedv commented on Jan 8, 2026

    @antonmedv
    Member

    I see. I will try to look at this issue. But I think another aporoach could be taken.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions