How to Modify Unexported Object in a Package

How to modify unexported object in a package

As it turns out, I only had to remove the unlockBinding, assign and lockBinding calls.

bar <- function(x) x + 1
assignInNamespace("C_rf", bar, ns="stats", pos="package:stats")

stats:::C_rf
# function(x) x + 1

rf(3, 2, 2)
#Error in .Call(C_rf, n, df1, df2) :
# first argument must be a string (of length 1) or native symbol reference

How to add unexported functions to R Package

R does not provide infrastructure for hiding source code[1]. Doing that is against the R developers' values and wishes.

So, what you want to do is not possible with R.

[1] http://r.789695.n4.nabble.com/how-to-hide-code-of-any-function-td4474822.html

Is there any way to access private fields of a struct from another package?

There is a way to read unexported members using reflect (in Go < 1.7)

func read_foo(f *Foo) {
v := reflect.ValueOf(*f)
y := v.FieldByName("y")
fmt.Println(y.Interface())
}

However, trying to use y.Set, or otherwise set the field with reflect will result in the code panicking that you're trying to set an unexported field outside the package.

In short: unexported fields should be unexported for a reason, if you need to alter them either put the thing that needs to alter it in the same package, or expose/export some safe way to alter it.

That said, in the interest of fully answering the question, you can do this (and have to do it this way in Go >= 1.7)

func change_foo(f *Foo) {
// Since structs are organized in memory order, we can advance the pointer
// by field size until we're at the desired member. For y, we advance by 8
// since it's the size of an int on a 64-bit machine and the int "x" is first
// in the representation of Foo.
//
// If you wanted to alter x, you wouldn't advance the pointer at all, and simply
// would need to convert ptrTof to the type (*int)
ptrTof := unsafe.Pointer(f)
ptrTof = unsafe.Pointer(uintptr(ptrTof) + uintptr(8)) // Or 4, if this is 32-bit

ptrToy := (**Foo)(ptrTof)
*ptrToy = nil // or *ptrToy = &Foo{} or whatever you want

}

This is a really, really bad idea. It's not portable, if int ever changes in size it will fail, if you ever rearrange the order of the fields in Foo, change their types, or their sizes, or add new fields before the pre-existing ones this function will merrily change the new representation to random gibberish data without telling you. I also think it might break garbage collection for this block.

Please, if you need to alter a field from outside the package either write the functionality to change it from within the package or export it.

Edit2: Since you mention White Box testing, note that if you name a file in your directory <whatever>_test.go it won't compile unless you use go test, so if you want to do white box testing, at the top declare package <yourpackage> which will give you access to unexported fields, and if you want to do black box testing then you use package <yourpackage>_test.

If you need to white box test two packages at the same time, however, I think you may be stuck and may need to rethink your design.

Unexported object imported by a ':::' call: 'tsfeatures:::scalets'

Here you could find the answer.
https://github.com/drsimonj/twidlr/issues/16

Summing up there are many options:

  • Contact package authors and ask them to export the relevant function.
  • Copy the function source code and cite the author appropriately. Use roxygen2 @references or manually \references in man file. In my opinion reference at the level of function is satisfactory if this function is one of many in your package. Remember that the specific function might depends on many others from the package, so then a lot of code have to be copied.
  • Another trick is using getFromNamespace() fun <- utils::getFromNamespace("fun", "pkg"). When you building a package the order and place of functions is not relevant (unless you use S4 or other exotic objects).

How to use an un exported object from third party package as return type in golang?

the package client // import "github.com/influxdata/influxdb/client/v2"
has exported Client interface so use client.Client instead of *client.client:

package influxclient

import (
"log"
"time"

"github.com/influxdata/influxdb/client/v2"
//"net/http"
"fmt"
"reflect"
)

const (
INFLUXDB_NAME = "XXXX"
USERNAME = "YYYY"
PASSWORD = "ZZZZ"
HOST = "http://localhost:8086"
)

var c = getHTTPClient()

func test() {
// Create a new point batch
bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
Database: INFLUXDB_NAME,
Precision: "s",
})

// Create a point and add to batch
tags := map[string]string{"cpu": "cpu-total"}
fields := map[string]interface{}{
"idle": 10.1,
"system": 53.3,
"user": 46.6,
}
fmt.Println(reflect.TypeOf(c))
pt, _ := client.NewPoint("cpu_usage", tags, fields, time.Now())
bp.AddPoint(pt)

// Write the batch
c.Write(bp)
}

//publish metrics to metrics db
func PublishMetrics(metricName string, tags map[string]string, fields map[string]interface{}, time time.Time) error {
fmt.Println("type of client c ", reflect.TypeOf(c))
// Create a new point batch
bp, err := client.NewBatchPoints(client.BatchPointsConfig{
Database: INFLUXDB_NAME,
Precision: "s",
})
if err != nil {
return err
}
pt, err := client.NewPoint(metricName, tags, fields, time)
if err != nil {
return err
}
bp.AddPoint(pt)
// Write the batch
c.Write(bp)
return nil
}

func getHTTPClient() client.Client {
//make http client for metrics db
c, err := client.NewHTTPClient(client.HTTPConfig{
Addr: HOST,
Username: USERNAME,
Password: PASSWORD,
})
if err != nil {
log.Printf("FATAL :: Error occured in getting influxdb metric client %s ", err.Error())
}
return c
}

Modify package function

I finally found a solution that should work in all situations!

environment(customGenomePlot) <- asNamespace('snapCGH')
assignInNamespace("genomePlot", customGenomePlot, ns = "snapCGH")

The call to environment() assures that the function will be able to call other hidden functions from the package.

The call to assignInNamespace() assures that other functions from the package will call your updated version of the function.

It is possible that in certain situation, you need only one of these, but in general you need both. I struggled to find this general solution, found many other which are not working in some cases, like this (need opposite order), or this (misses the second part), or this (throws the error "cannot add bindings to a locked environment").

Golang struct literal syntax with unexported fields

You can only use composite literals to create values of struct types defined in another package if you use keyed values in the literal, because then you are not required to provide initial values for all fields, and so you can leave out unexported fields (which only the declaring package can set / change).

If the type is declared in the same package, you can set unexported fields too:

t := Thing{
Name: "the name",
someUnexported: 23,
}

But you can only provide initial values for exported fields if the type is declared in another package, which is not a surprise I guess:

t := otherpackage.Thing{
Name: "the name",
// someUnexported will implicitly be its zero value
}

If you need values of the struct where the unexported fields have values other than the zero value of their types, the package itself must export some kind of constructor or initializer (or setter method), because from the outside (of the package), you can't change / set unexported fields.

See related question: How to clone a structure with unexported field?

JSON and dealing with unexported fields

There is a technical reason. The json library does not have the power to view fields using reflect unless they are exported. A package can only view the unexported fields of types within its own package

In order to deal with your problem, what you can do is make an unexported type with exported fields. Json will unmarshal into an unexported type if passed to it without a problem but it would not show up in the API docs. You can then make an exported type that embeds the unexported type. This exported type would then need methods to implement the json.Marshaler and json.Unmarshaler interfaces.

Note: all code is untested and may not even compile.

type jsonData struct {
Field1 string
Field2 string
}

type JsonData struct {
jsonData
}

// Implement json.Unmarshaller
func (d *JsonData) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &d.jsonData)
}

// Getter
func (d *JsonData) Field1() string {
return d.jsonData.Field1
}


Related Topics



Leave a reply



Submit