Skip to content

Commit

Permalink
[R-package] make finalize() in R6 classes private (#6833)
Browse files Browse the repository at this point in the history
  • Loading branch information
jameslamb authored Feb 17, 2025
1 parent 604e2c5 commit 3fad53b
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 62 deletions.
2 changes: 1 addition & 1 deletion R-package/DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Suggests:
Depends:
R (>= 3.5)
Imports:
R6 (>= 2.0),
R6 (>= 2.4.0),
data.table (>= 1.9.6),
graphics,
jsonlite (>= 1.0),
Expand Down
21 changes: 11 additions & 10 deletions R-package/R/lgb.Booster.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,6 @@ Booster <- R6::R6Class(
record_evals = list(),
data_processor = NULL,

# Finalize will free up the handles
finalize = function() {
.Call(
LGBM_BoosterFree_R
, private$handle
)
private$handle <- NULL
return(invisible(NULL))
},

# Initialize will create a starter booster
initialize = function(params = list(),
train_set = NULL,
Expand Down Expand Up @@ -711,6 +701,17 @@ Booster <- R6::R6Class(
set_objective_to_none = FALSE,
train_set_version = 0L,
fast_predict_config = list(),

# finalize() will free up the handles
finalize = function() {
.Call(
LGBM_BoosterFree_R
, private$handle
)
private$handle <- NULL
return(invisible(NULL))
},

# Predict data
inner_predict = function(idx) {

Expand Down
30 changes: 15 additions & 15 deletions R-package/R/lgb.Dataset.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,6 @@ Dataset <- R6::R6Class(
cloneable = FALSE,
public = list(

# Finalize will free up the handles
finalize = function() {
.Call(
LGBM_DatasetFree_R
, private$handle
)
private$handle <- NULL
return(invisible(NULL))
},

# Initialize will create a starter dataset
initialize = function(data,
params = list(),
Expand Down Expand Up @@ -210,7 +200,7 @@ Dataset <- R6::R6Class(
if (is.null(private$raw_data)) {
stop(paste0(
"Attempting to create a Dataset without any raw data. "
, "This can happen if you have called Dataset$finalize() or if this Dataset was saved with saveRDS(). "
, "This can happen if the Dataset's finalizer was called or if this Dataset was saved with saveRDS(). "
, "To avoid this error in the future, use lgb.Dataset.save() or "
, "Dataset$save_binary() to save lightgbm Datasets."
))
Expand Down Expand Up @@ -608,7 +598,7 @@ Dataset <- R6::R6Class(
# If updating failed but raw data is available, modify the params
# on the R side and re-set ("deconstruct") the Dataset
private$params <- new_params
self$finalize()
private$finalize()
})
}
return(invisible(self))
Expand Down Expand Up @@ -649,7 +639,7 @@ Dataset <- R6::R6Class(
private$categorical_feature <- categorical_feature

# Finalize and return self
self$finalize()
private$finalize()
return(invisible(self))

},
Expand Down Expand Up @@ -681,7 +671,7 @@ Dataset <- R6::R6Class(
private$reference <- reference

# Finalize and return self
self$finalize()
private$finalize()
return(invisible(self))

},
Expand Down Expand Up @@ -713,6 +703,16 @@ Dataset <- R6::R6Class(
info = NULL,
version = 0L,

# finalize() will free up the handles
finalize = function() {
.Call(
LGBM_DatasetFree_R
, private$handle
)
private$handle <- NULL
return(invisible(NULL))
},

get_handle = function() {

# Get handle and construct if needed
Expand Down Expand Up @@ -749,7 +749,7 @@ Dataset <- R6::R6Class(
private$predictor <- predictor

# Finalize and return self
self$finalize()
private$finalize()
return(invisible(self))

}
Expand Down
30 changes: 12 additions & 18 deletions R-package/R/lgb.Predictor.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,6 @@ Predictor <- R6::R6Class(
cloneable = FALSE,
public = list(

# Finalize will free up the handles
finalize = function() {

# Check the need for freeing handle
if (private$need_free_handle) {

.Call(
LGBM_BoosterFree_R
, private$handle
)
private$handle <- NULL

}

return(invisible(NULL))

},

# Initialize will create a starter model
initialize = function(modelfile, params = list(), fast_predict_config = list()) {
private$params <- .params2str(params = params)
Expand Down Expand Up @@ -531,5 +513,17 @@ Predictor <- R6::R6Class(
.equal_or_both_null(private$fast_predict_config$num_iteration, num_iteration)
)
}

# finalize() will free up the handles
, finalize = function() {
if (private$need_free_handle) {
.Call(
LGBM_BoosterFree_R
, private$handle
)
private$handle <- NULL
}
return(invisible(NULL))
}
)
)
4 changes: 2 additions & 2 deletions R-package/src/lightgbm_R.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ void _DatasetFinalizer(SEXP handle) {
SEXP LGBM_NullBoosterHandleError_R() {
Rf_error(
"Attempting to use a Booster which no longer exists and/or cannot be restored. "
"This can happen if you have called Booster$finalize() "
"This can happen if the Booster's finalizer was called "
"or if this Booster was saved through saveRDS() using 'serializable=FALSE'.");
return R_NilValue;
}
Expand All @@ -285,7 +285,7 @@ void _AssertDatasetHandleNotNull(SEXP handle) {
if (Rf_isNull(handle) || !R_ExternalPtrAddr(handle)) {
Rf_error(
"Attempting to use a Dataset which no longer exists. "
"This can happen if you have called Dataset$finalize() or if this Dataset was saved with saveRDS(). "
"This can happen if the Dataset's finalizer was called or if this Dataset was saved with saveRDS(). "
"To avoid this error in the future, use lgb.Dataset.save() or Dataset$save_binary() to save lightgbm Datasets.");
}
}
Expand Down
6 changes: 3 additions & 3 deletions R-package/tests/testthat/test_Predictor.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
library(Matrix)

test_that("Predictor$finalize() should not fail", {
test_that("Predictor's finalizer should not fail", {
X <- as.matrix(as.integer(iris[, "Species"]), ncol = 1L)
y <- iris[["Sepal.Length"]]
dtrain <- lgb.Dataset(X, label = y)
Expand All @@ -21,11 +21,11 @@ test_that("Predictor$finalize() should not fail", {

expect_false(.is_null_handle(predictor$.__enclos_env__$private$handle))

predictor$finalize()
predictor$.__enclos_env__$private$finalize()
expect_true(.is_null_handle(predictor$.__enclos_env__$private$handle))

# calling finalize() a second time shouldn't cause any issues
predictor$finalize()
predictor$.__enclos_env__$private$finalize()
expect_true(.is_null_handle(predictor$.__enclos_env__$private$handle))
})

Expand Down
6 changes: 3 additions & 3 deletions R-package/tests/testthat/test_dataset.R
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ test_that("Dataset$update_params() works correctly for recognized Dataset parame
}
})

test_that("Dataset$finalize() should not fail on an already-finalized Dataset", {
test_that("Dataset's finalizer should not fail on an already-finalized Dataset", {
dtest <- lgb.Dataset(
data = test_data
, label = test_label
Expand All @@ -361,11 +361,11 @@ test_that("Dataset$finalize() should not fail on an already-finalized Dataset",
dtest$construct()
expect_false(.is_null_handle(dtest$.__enclos_env__$private$handle))

dtest$finalize()
dtest$.__enclos_env__$private$finalize()
expect_true(.is_null_handle(dtest$.__enclos_env__$private$handle))

# calling finalize() a second time shouldn't cause any issues
dtest$finalize()
dtest$.__enclos_env__$private$finalize()
expect_true(.is_null_handle(dtest$.__enclos_env__$private$handle))
})

Expand Down
20 changes: 10 additions & 10 deletions R-package/tests/testthat/test_lgb.Booster.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
test_that("Booster$finalize() should not fail", {
test_that("Booster's finalizer should not fail", {
X <- as.matrix(as.integer(iris[, "Species"]), ncol = 1L)
y <- iris[["Sepal.Length"]]
dtrain <- lgb.Dataset(X, label = y)
Expand All @@ -15,11 +15,11 @@ test_that("Booster$finalize() should not fail", {

expect_false(.is_null_handle(bst$.__enclos_env__$private$handle))

bst$finalize()
bst$.__enclos_env__$private$finalize()
expect_true(.is_null_handle(bst$.__enclos_env__$private$handle))

# calling finalize() a second time shouldn't cause any issues
bst$finalize()
bst$.__enclos_env__$private$finalize()
expect_true(.is_null_handle(bst$.__enclos_env__$private$handle))
})

Expand Down Expand Up @@ -195,7 +195,7 @@ test_that("Loading a Booster from a text file works", {
lgb.save(bst, model_file)

# finalize the booster and destroy it so you know we aren't cheating
bst$finalize()
bst$.__enclos_env__$private$finalize()
expect_null(bst$.__enclos_env__$private$handle)
rm(bst)

Expand Down Expand Up @@ -238,7 +238,7 @@ test_that("boosters with linear models at leaves can be written to text file and
preds <- predict(bst, X)
model_file <- tempfile(fileext = ".model")
lgb.save(bst, model_file)
bst$finalize()
bst$.__enclos_env__$private$finalize()
expect_null(bst$.__enclos_env__$private$handle)
rm(bst)

Expand Down Expand Up @@ -275,7 +275,7 @@ test_that("Loading a Booster from a string works", {
model_string <- bst$save_model_to_string()

# finalize the booster and destroy it so you know we aren't cheating
bst$finalize()
bst$.__enclos_env__$private$finalize()
expect_null(bst$.__enclos_env__$private$handle)
rm(bst)

Expand Down Expand Up @@ -313,7 +313,7 @@ test_that("Saving a large model to string should work", {
expect_gt(nchar(model_string), 1024L * 1024L)

# finalize the booster and destroy it so you know we aren't cheating
bst$finalize()
bst$.__enclos_env__$private$finalize()
expect_null(bst$.__enclos_env__$private$handle)
rm(bst)

Expand Down Expand Up @@ -383,7 +383,7 @@ test_that("If a string and a file are both passed to lgb.load() the file is used
lgb.save(bst, model_file)

# finalize the booster and destroy it so you know we aren't cheating
bst$finalize()
bst$.__enclos_env__$private$finalize()
expect_null(bst$.__enclos_env__$private$handle)
rm(bst)

Expand Down Expand Up @@ -1508,7 +1508,7 @@ test_that("boosters with linear models at leaves can be written to RDS and re-lo
preds <- predict(bst, X)
model_file <- tempfile(fileext = ".rds")
saveRDS(bst, file = model_file)
bst$finalize()
bst$.__enclos_env__$private$finalize()
expect_null(bst$.__enclos_env__$private$handle)
rm(bst)

Expand Down Expand Up @@ -1562,7 +1562,7 @@ test_that("Booster's print, show, and summary work correctly", {
.has_expected_content_for_fitted_model(log_txt)

#--- should not fail for finalized models ---#
model$finalize()
model$.__enclos_env__$private$finalize()

# print()
log_txt <- capture.output({
Expand Down

0 comments on commit 3fad53b

Please sign in to comment.